Iced: Is it possible to `run()` an already-instantiated instance of `Application`?

Created on 6 Apr 2020  路  9Comments  路  Source: hecrj/iced

I am loosely coupling my GUI dependencies using the Ports and Adapters (aka Hexagonal Architecture) pattern.

If I am understanding the docs correctly, it appears that if my builder pattern instantiates an Application via Application::new(), there is no way to run() that particular instance. Have I missed something?

question

All 9 comments

No, it is not possible.

Application::run will never return in native platforms. Therefore, it isn't composable. You are only supposed to have one Application alive in a given process: the one run creates.

Thanks, @hecrj. For clarity, I do only have 1 Application instance. I just wish to configure it before running it. But thanks for the confirmation--I understand that if instances were allowed to be run, one could (attempt to) invoke multiple instances. At least I am certain I am not misunderstanding the API. I will figure something out.

You should be able to use the flags field in Settings to configure your application on construction in Application::new.

Unfortunately because Flags is in iced::Settings it is difficult for me to extract and use; once iced::Settings is used, Flags is gone, and I cannot just extract Flags as this invalidates iced::Settings (without additional gymnastics, that is).

You only need iced::Settings to call Application::run and after that you lose complete control of the process. It will never return.

I do not understand why you can't generate iced::Settings at the end of your program right when calling Application::run.

I'll try to provide an cut-down example. But the jist is trying to get iced to conform to my domain API, which is a simple builder pattern:

fn main() -> Result<()> {
    AppBuilder::new()
        .set_window_state(...)
        .set_title(...)
        .build()?
        .run()
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=eb94082e06d80ba7d5d6eae6ffc00013

I am puzzled by some of these errors, especially that last one where iced::Settings<iced::Settings::<AppSettings>> is expected (note the nesting), rather than just iced::Settings<AppSettings>.

Any thoughts?

Incidentally, any reason my iced::Application::run()'s return signature isn't divergent (-> !) since it doesn't return?

I am puzzled by some of these errors, especially that last one where iced::Settings> is expected (note the nesting), rather than just iced::Settings.

Your Application::Flags should be AppSettings.

However, I still don't understand the reason why you need an AppBuilder just to call a single function with some parameters __exactly once__ in your entire codebase. Why are you building an abstraction for that?

And if you want to go that way, why not simply have a SettingsBuilder instead, and then:

fn main() -> Result<()> {
    let settings: iced::Settings<AppSettings> = SettingsBuilder::new()
        .set_window_state(...)
        .set_title(...)
        .build()?;

    App::run(settings)  
}

I'm probably missing part of the picture :sweat_smile:

Incidentally, any reason my iced::Application::run()'s return signature isn't divergent (-> !) since it doesn't return?

It does return on web platforms. We do need to change the iced_winit one, though.

Well that was it, @hecrj -- I feel a bit dumb missing that part! Very grateful for your help.

I was definitely using the API wrong; the entanglement issue I was mentioning earlier--the custom field I wanted having to be consumed--was purely an artifact of my (incorrect) mental model. Once you clued me in to iced::Application trait needing to be AppSettings and not iced::Settings<AppSettings>, all kinds of issues disappared and the app was up and running in 5 minutes. :)

just to call a single function with some parameters exactly once in your entire codebase

and

why not simply have a SettingsBuilder instead
I am using Ports & Adapters pattern to decouple my application from its dependencies. If my application domain included anything from iced (such as `iced::Settings), then it would be much more expensive to adapt other GUI frameworks to my application.

All of the above must be confined to the adapter domain for my app to be loosely coupled. The decoupling is not a function of how often the interface is called (once or many times); It's a matter of not having any dependency types present in the application domain.

When this is done, it is possible to change UI frameworks purely by changing adapters (I have a coffee adapter implementations working so I can compare the performance of my application between two of your crates, fore example). But in general, P&A makes it feasible for the application author to switch dependencies for any reason (new crates, terminated support, security concerns, etc., etc.)

I am using the builder pattern to allow a variety of configuration parameters to be optionally specified. The policy of what to do with an unspecified parameter is confined to one place, namely the builder as opposed to all throughout my application, potentially redundantly, or worse, inconsistently, in different places.

Further, if a combination of settings is selected that a particular dependency does not support, that will be discovered at build time (or mitigated ahead of time by the implementation of the dependency-specific Builder adapter).

Hope that helps! Thanks again for the clue I so badly needed! :100:

I was definitely using the API wrong; the entanglement issue I was mentioning earlier--the custom field I wanted having to be consumed--was purely an artifact of my (incorrect) mental model. Once you clued me in to iced::Application trait needing to be AppSettings and not iced::Settings, all kinds of issues disappared and the app was up and running in 5 minutes. :)

Glad to hear! I'll add an example in the Flags documentation to avoid further confusion for other users.

Thank you for the details!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hecrj picture hecrj  路  3Comments

CallistoM picture CallistoM  路  3Comments

Shootertrex picture Shootertrex  路  3Comments

rowungiles picture rowungiles  路  4Comments

pbspbsingh picture pbspbsingh  路  4Comments