Why does my version of the Elmish.WPF Sample NewWindow (XAML code and F# Core) emit the error ...
The same line emits the warning...
Why am I getting this error and warning?
What I am doing is merging the Elmish.WPF Samples SingleCounter (XAML code and F# Core) and NewWindow (XAML code and F# Core) to have the Model
, bindings()
, and Msg
parts in Program.fs
instead of App.fs
(as it was in the NewWindow sample).
My goal is to make a SimpleCounter able to open a NewWindow.
The XAML code passes Func<Window2>
into the F# code here...
let main mainWindow (createWindow2: Func<#Window>)
...I define bindings
as...
let bindings = Platform.bindings createWindow_Window2
I am down to the one compiler error I mentioned above (and that also appears in line beginning "let bindings = ..." below)...
let main mainWindow (createWindow_Window2: Func<#Window>) =
let logger =
LoggerConfiguration()
.MinimumLevel.Override("Elmish.WPF.Update", Events.LogEventLevel.Verbose)
.MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose)
.MinimumLevel.Override("Elmish.WPF.Performance", Events.LogEventLevel.Verbose)
.WriteTo.Console()
.CreateLogger()
let createWindow_Window2 =
let window = createWindow_Window2.Invoke()
window.Owner <- mainWindow
window
let bindings = Platform.bindings createWindow_Window2
WpfProgram.mkProgramWithCmdMsg (fun _ -> m_init, []) update bindings toCmd
|> WpfProgram.withLogger (new SerilogLoggerFactory(logger))
|> WpfProgram.startElmishLoop mainWindow
The top of Program.bindings
is defined as ...
let bindings (createWindow_Window2: unit -> #Window) () : Binding<Model, Msg> list = [
"Window_Window2_Show|> Binding.cmd Window_AboutProduct_Show
"Window_Window2" |> Binding.subModelWin(
Window_Window2.get >> WindowState.ofOption,
snd,
Window_Window2ct.mapInOutMsg,
Window_Window2_Module.Window_Window2.bindings,
createWindow_Window2,
isModal = true)
...bindings continue but are not relevant to this question...
... and reports no errors!
The compiler seems to think Platform.bindings
is expecting unit -> `a
when createWindow_Window2
is correctly typed as unit -> #Window
.
You can see the call into Program.fs:main
is correctly called from App.xaml.cs
with a lambda function returning a Window2
as follows...
private void StartElmish(object sender, EventArgs e)
{
this.Activated -= StartElmish;
Program.main(MainWindow, () => new Window2());
}
So my question is why am I getting this mismatch type error when it seems I am passing the correct types?
Thank you!
A big thank you to: Brian Berns, Bent Tranberg, and Tomas Petricek for helping me!
The answer to my problem was astonishingly simple to an expert but to a relative novice only yielded after meticulous comparison with the working Elmish.WPF code for NewWindow.
For easy comparison I have pushed up to rfreytag/Elmish.WPF a version of the NewWindow (XAML code and F# Core) sample that compiles and runs (REMEMBER to build the NewWindow sample).
This version of NewWindow (XAML code and F# Core) when compiled shows the error and warning I reported above …
The type 'unit -> 'a' is not compatible with the type 'Window'.
See also C:\Workspace\Elmish.WPF\src\Samples\AnotherNewWindow.Core\Program.fs(78,72)-(78,79).
...and the warning...
This construct causes code to be less generic than indicated by its
type annotations. The type variable implied by the use of a '#', '_'
or other type annotation at or near
'C:\Workspace\Elmish.WPF\src\Samples\AnotherNewWindow.Core\Program.fs(78,72)-(78,79)'
has been constrained to be type 'unit -> 'a'.
To see the precise fix you can compare the working and breaking branches on my copy of Elmish.WPF. Which is that I had forgotten the ()
following the definition of let createWindow_Window2 =
...
let createWindow_Window2 =
let window = createWindow_Window2.Invoke()
window.Owner <- mainWindow
window
... returns the function () -> Window
while the correct ...
let createWindow_Window2 () =
let window = createWindow_Window2.Invoke()
window.Owner <- mainWindow
window
... returns the needed Window
.
A newbie looks at unit → ‘a
and doesn’t immediately recognize it as a function. And of course, functions are not C# Window
objects.
Did not help me that the error message doesn’t follow the F# form of...
expecting a <type sought by context>
but was given a <passed in type>
...which has become familiar from working with the F# compiler.
Not sure why this message diverged from that pattern. Maybe someone can explain that?
The warning is alerting to the less-specific #Window
(see # ‘flexible type’ definition) possibly clashing at run-time with the unit → ‘a
function.
As usual, learning a new framework means learning the compiler and linker messages.