开发者

Module values in F# don't get initialized. Why?

开发者 https://www.devze.com 2023-03-18 20:38 出处:网络
I got a strange behavior when I used F#. When I use let binding in a module, and if the value is created from a constructor, then it\'s uninitialized when used outside. (I used it from C# using Module

I got a strange behavior when I used F#. When I use let binding in a module, and if the value is created from a constructor, then it's uninitialized when used outside. (I used it from C# using ModuleName.s2 or ModuleName.f())

//in a module
let s1 = "1" //normal
let s2 = new String('i', 5) /开发者_如何转开发/null

let f () =
    s2.Equals("something") //Exception

Is this a normal behavior? Thanks in advance.

EDIT: For the purpose of debugging, I choose to compile it as an executable. This may be the problem as other people pointed out.


In an F# library, modules are initialized via static constructors which ensure that initialization occurs prior to any of the module's values being used. By contrast, in an F# executable, this initialization is performed in the application's entry point. This means that if another assembly references the F# application (regardless of the language the other application is written in), the initialization code won't be run.

UPDATE

Brian pointed me to this part of the spec, which indicates that this is the expected behavior.

It looks like one workaround would be to provide an explicit entry point, like this:

[<EntryPoint>]
let main _ =
    0

You can then call this main method from your C# app to ensure that the module's contents are properly initialized.

UPDATE 2

I was misreading the spec - you do not need to actually call the explicit entry point from the referencing assembly. Its mere presence will cause the initialization to occur correctly.


For some reason, SomeModule.s2 is implemented as a (read-only) property that returns the value of the unspeakable static field <StartupCode$FS>.$Program.s2@9. If you compile as an application, that field is initialized in the main method. When used from your C# code, this method is not called, so the field is not initialized.

If you compile as a library, the code is the same, except the field is initialized in the static constructor of the $Program class, so it should work when used from C#.

The reason s1 always works is optimization: the F# compiler understands it's a constant and implements f() as "1".Equals("something").

0

精彩评论

暂无评论...
验证码 换一张
取 消