Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute module do block?

Tags:

f#

I need to do some setup in a module that I wanted to accomplish by leveraging a do block. Strangely though, my do block never seems to get hit.

Even stranger, If I load the module code into fsi, it does get hit. Here is my example:

Main.fs

[<EntryPoint>]
let main args = 
    printfn "%b" TestNamespace.M.x
    0

TestModule.fs

namespace TestNamespace

module M = 
    do
        printfn "In do"
        failwith "Error" // this is line 6

    let x  = true

When I run the compiled executable I get

>test.exe
 true

Why didn't the exception get thrown? If I run the module in FSI by itself I get

In do
System.Exception: Error
    at <StartupCode$FSI_0006>.$FSI_0006.main@() in    C:\Projects\Personal2\Playground\fsscripts\fsscripts\TestModule.fs:line 6
Stopped due to error

So it got the exception.

I see that in the decompliation that the do initializers get rolled into a seperate class

namespace \u003CStartupCode\u0024fsscripts\u003E
{
  internal static class \u0024Library1
  {
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    [CompilerGenerated]
    [DebuggerNonUserCode]
    internal static int init\u0040;

    static \u0024Library1()
    {
      ExtraTopLevelOperators.PrintFormatLine<Unit>((PrintfFormat<Unit, TextWriter, Unit, Unit>) new PrintfFormat<Unit, TextWriter, Unit, Unit, Unit>("In do"));
      Operators.FailWith<Unit>("Error");
      bool x = M.x;
    }
  }
}

VS the actual module code:

namespace TestNamespace
{
  [CompilationMapping(SourceConstructFlags.Module)]
  public static class M
  {
    public static bool x
    {
      [DebuggerNonUserCode] get
      {
        return true;
      }
    }
  }
}

So how do I make sure the do block actually gets executed?

--

Edit, given the above example counts as a simple constant expression so won't produce an observable initialization, why does the following also not work?

[<EntryPoint>]
let main args = 
    printfn "%d" (TestNamespace.M.x id 1)
    0
namespace TestNamespace

module M = 
    do
        printfn "In do"
        failwith "Error"

    let x f a = f a

This prints out 1 no problem.


Edit, after having re-read Tomas's comments its because a function is considered a constant expression.

like image 739
devshorts Avatar asked Nov 01 '25 14:11

devshorts


1 Answers

For a good explanation of the problem, see the answer to this previous SO question. The important bit says:

the static initializer for the file is executed on first access of a value that has observable initialization

Now, "observable initialization" is somewhat tricky idea, but simple constant initialization definitely does not have observable initialization - that's why the do block is not executed. You can trick the compiler into thinking that there is some imperative action, for example by adding do ():

module M = 
    do
        printfn "In do"
        failwith "Error" // this is line 6

    let x = (do ()); true
like image 97
Tomas Petricek Avatar answered Nov 03 '25 12:11

Tomas Petricek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!