Initializing static fields in a type with no primary constructors

125 views
Skip to first unread message

Bruno Bozza

unread,
Sep 6, 2015, 10:54:21 PM9/6/15
to F# Discussions
Sorry to cross-post, as I asked this just yesterday on Stack Overflow (http://stackoverflow.com/questions/32419747/in-f-how-do-i-initialize-static-fields-in-a-type-with-no-primary-constructor).

I have an F# class that derives from a .net class with multiple constructors. To expose them all, I implement a type with no primary constructor. Now I would like to add a static field. How do I initialize the static field? Consider this:

type MyType =
    inherit DotNetType
    [<DefaultValue>] static val mutable private myStatic : int
    new () = { inherit DotNetType() }
    new (someArg:string) = { inherit DotNetType(someArg) }
How do I initialize the "myStatic" field in a way that runs exactly once if the type is used, and not at all if the type is never used? Essentially, I need the equivalent of a C# static constructor block. I am starting to suspect this to be a language issue, so I am open to workarounds. The goal is to have the value initialized exactly once, the first the type is accessed. 

Thanks,
Bruno

Gauthier Segay

unread,
Sep 7, 2015, 2:44:58 AM9/7/15
to fsharp-o...@googlegroups.com
Hello Bruno, could you look in "do binding":

https://msdn.microsoft.com/en-us/library/dd483473.aspx

there is static do and I think it's what you need.
> --
> --
> To post, send email to fsharp-o...@googlegroups.com
> To unsubscribe, send email to
> fsharp-opensou...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/fsharp-opensource
> ---
> You received this message because you are subscribed to the Google Groups
> "F# Discussions" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to fsharp-opensou...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Bruno Bozza

unread,
Sep 7, 2015, 3:21:49 AM9/7/15
to F# Discussions
"do" bindings, even static ones, are not allowed on a type with no primary constructor.I'm starting to think this may be a language issue.

Andrew Cherry

unread,
Sep 7, 2015, 3:27:43 AM9/7/15
to fsharp-o...@googlegroups.com
I suppose it might be - the F# way might simply be different. Perhaps there's an alternative to the static binding? If what you want is a value that's static, but only initialized if used, that sounds a bit like Lazy<_> - maybe that's a more F# approach? Without context I don't know though...

Bruno Bozza

unread,
Sep 7, 2015, 9:31:40 PM9/7/15
to F# Discussions
Context is that I am deriving from MemoryStream, which has like half a dozen constructors, and I need to initialize some static fields in my own class. I can think of a few workarounds, but are none quite satisfactory, and the thing is that there is already a way to do this in .net, the class constructor (.cctor, static constructor in C#), but I don't see how to generate one under these conditions (no primary constructor) in F#. 

Can't put it in 'a lazy (get it ;-)) because the lazy itself would have to be a static field in the same class, which therefore can't be initialized either (i.e.: I must use [<DefaultValue>]).

I understand why (instance) "let" and "do" bindings are not allowed unless you have a primary constructor, but their static versions should be fine, at least in the absence of generics. Even in the presence of generics, C# must do something, which I understand might be ugly, but outlawing any static initialization seem quite drastic.  

Bruno

Bruno Bozza

unread,
Sep 7, 2015, 9:39:39 PM9/7/15
to F# Discussions
Ok. Quick stackoverflow research tells me that C# calls the static constructor once for each close type. Sounds reasonable to me. 

Bruno Bozza

unread,
Sep 15, 2015, 6:18:56 PM9/15/15
to F# Discussions
To be clear, the stack overflow check didn't answer my original question - just the incidental "what does C# do?" part. I worked around my problem, but I still have found no way to initialize statics in a type without a primary constructor.

Jared Hester

unread,
Sep 27, 2015, 1:52:00 PM9/27/15
to F# Discussions

This uses a primary constructor but I think it still accomplishes what you were looking for

type DotNetType = 
    val private _x:string
    new(x:string) = { _x = x }
    new()         = DotNetType("")

type MyType private (x:obj) =
    inherit DotNetType()
    static let mutable initialized = false
    static let mutable config    = 0 
    static member private Init() =
        if initialized = true then () else
            initialized <- true
            config <- config + 50 // add to self to see if called
    static member SConfig = string config
    member __.IConfig = string config
    new() = 
        MyType.Init(); MyType obj
    new(msg:string,cnt:int) =
        MyType.Init(); 
        printfn "Secondary ConstructorI #%i" cnt
        MyType 45 
    new(msg:string,cnt:float) =
        MyType.Init(); 
        printfn "Secondary ConstructorF #%A\n%s" cnt msg
        MyType "" 
    member val InstProp = "allo" with get, set
;;
printfn "Before First Construction - %s" MyType.SConfig              
let x1 = MyType("greetings",20.0,InstProp = " x_1 ") 
printfn "After First Construction - %s" MyType.SConfig
printfn "Static config via {x1} - %s\n" x1.IConfig

printfn "Before Second Construction - %s" MyType.SConfig              
let x2 = MyType()
x2.InstProp <- " x_2 " 
printfn "After Second Construction - %s" MyType.SConfig
printfn "Static config via {x2} - %s\n" x1.IConfig
printfn "Built {%s} & {%s} but stayed at - %s" 
        x1.InstProp x2.InstProp MyType.SConfig

The FSI Output is -

type DotNetType =
  class
    new : unit -> DotNetType
    new : x:string -> DotNetType
    val private _x: string
  end
type MyType =
  class
    inherit DotNetType
    new : unit -> MyType
    private new : x:obj -> MyType
    new : msg:string * cnt:int -> MyType
    new : msg:string * cnt:float -> MyType
    member IConfig : string
    member InstProp : string
    member InstProp : string with set
    static member private Init : unit -> unit
    static member SConfig : string
  end

> Before First Construction - 0
Secondary ConstructorF #20.0
greetings
After First Construction - 50
Static config via {x1} - 50

Before Second Construction - 50
After Second Construction - 50
Static config via {x2} - 50

Built { x_1 } & { x_2 } but stayed at - 50

val x1 : MyType
val x2 : MyType
val it : unit = ()

>
Reply all
Reply to author
Forward
0 new messages