Answered Singletone implementation

  • Wednesday, July 18, 2012 5:00 PM
     
      Has Code

    Hi,  F# people!

    Please advice, I've found that kind of Singleton implementation in F# somewhere on msdn

    type Singleton private() =
        static let instance = new Singleton()
        static member Instance = instance

    And it's pretty good. (Clear and just 2 lines)

    But what do you think of this idea

    type Singleton2 private() =
        static member Instance = lazy(new Singleton2())


    I mean to use lazy evaluation here but don't quite understand how to make it work?

    ========================

    And another question:

    type NameCollection = { Name : string SecName : string } [<Sealed>] type Singleton private() = static let instance = new Singleton() static member Instance = instance member public this.UsefulPartExample = [| {Name = "Pam"; SecName = "Pamovich"} {Name = "Sam"; SecName = "Fisher"} |] let m = Singleton.Instance

    //And I thought that next line should have changed the 'instance' property but it didn't m.UsefulPartExample.[0] <- {Name = "Ivy"; SecName = "Red"}

    (* FSI output is the same

    val it : NameCollection [] =
      [|{Name = "Pam";
         SecName = "Pamovich";}; {Name = "Sam";
                                  SecName = "Fisher";}|] *)

    What should i write to make 'NameCollection' changeable? Thanks in advance.

All Replies

  • Wednesday, July 18, 2012 5:25 PM
     
      Has Code

    Your implementation of this.UsefulPartExample property returns freshly created array every time someone access it.

    To make it changeable you have to implement internal array value:

    [<Sealed>]
    type Singleton private() =
        let upa = 
            [|
                {Name = "Pam"; SecName = "Pamovich"}
                {Name = "Sam"; SecName = "Fisher"}    
            |]
        static let instance = new Singleton()
        static member Instance = instance
        member public this.UsefulPartExample = upa 
    

    now you can change internal array via property:

    m.UsefulPartExample.[0] <- {Name = "Ivy"; SecName = "Red"}
    


    Petr

  • Wednesday, July 18, 2012 5:35 PM
     
      Has Code

    To implement lazy creation you can do this way, for example:

    [<Sealed>]
    type Singleton private() =
        let upa = 
            [|
                {Name = "Pam"; SecName = "Pamovich"}
                {Name = "Sam"; SecName = "Fisher"}    
            |]
        do printfn "Creating"
        static let instance = lazy(new Singleton())
        static member Instance = instance.Force()
        member public this.UsefulPartExample = upa 
         
    let m = Singleton.Instance
    let m1 = Singleton.Instance
    
    As per MSDN (http://msdn.microsoft.com/en-us/library/dd233247.aspx) Force() will be called only once. You can see it if you'll access Instance property several times. Printout "Creating" will appear only once.

    Petr

  • Wednesday, July 18, 2012 7:20 PM
    Moderator
     
      Has Code

    Properties are evaluated each time they are accessed, so you'll be creating a new lazy instance each time you access your property.  Note that F# 3.0 includes an auto-property feature which you could use like this:

    type Singleton private() =
        static member val Instance = new Singleton()
    
    With this feature, the right hand side is evaluated only once.  You could also use lazy on the right hand side if you wanted to, though this only makes sense if there is some significant initialization cost that you'd like to delay.
  • Wednesday, July 18, 2012 10:06 PM
    Moderator
     
     
    (to be very clear, 'Force' is called each time you access the property, but lazy.Force() only does work the first time, and just returns the cached value for each subsequent call)

    Brian McNamara [MSFT]

  • Thursday, July 19, 2012 7:49 AM
     
      Has Code
    Thanks everyone for your answers! But why it's so strange with the initialization? I mean 

    [<Sealed>] type Singleton private() =

    //It's not obvious for me, why it's neccessary to create a binding first, and let upa = [| {Name = "Pam"; SecName = "Pamovich"} {Name = "Sam"; SecName = "Fisher"} |] static let instance = new Singleton() static member Instance = instance

    //...only then pass the value here so that property became changeable member public this.UsefulPartExample = upa

    So, why it isn't working without internal array, what are mechanisms beyound that?

  • Thursday, July 19, 2012 12:18 PM
     
     Answered Has Code

    Your initial implementation of the property:

       member public this.UsefulPartExample = 
            [|
                {Name = "Pam"; SecName = "Pamovich"}
                {Name = "Sam"; SecName = "Fisher"}    
            |]

    created a new instance of an array with the same records every time you call this member. It was roughly equal to:

       member public this.UsefulPartExample = 
            new NameCollection[] {...}

    But let binding (let upa = ...) happens in the class constructor because it placed before any member declaration. It occurs only once and member this.UsefulPartExample returns this object which you can perform operations on. In this case identifier 'upa' is an internal field of the class.

    Also you can test that your initial member implementation creates new array this way:

    [<Sealed>]
    type Singleton private() =
        do printfn "Creating"
        static let instance = lazy(new Singleton())
        static member Instance = instance.Force()
        member public this.UsefulPartExample =  
            [|
                {Name = "Pam"; SecName = "Pamovich"}
                {Name = "Sam"; SecName = "Fisher"}    
            |]
    
    let m = Singleton.Instance
    let arr1 = m.UsefulPartExample // arr1 is freshly created with 'Pam' and 'Sam'
    arr1.[0] <- {Name = "Ivy"; SecName = "Red"}
    let arr2 = m.UsefulPartExample // arr2 is another freshly created array with 'Pam' and 'Sam'  
    arr2.[0] <- {Name = "John"; SecName = "Doe"}


    Petr




    • Edited by Plepilov Thursday, July 19, 2012 12:29 PM
    • Marked As Answer by SmartWizard Thursday, July 19, 2012 1:27 PM
    •  
  • Thursday, July 19, 2012 1:27 PM
     
     
    Thank you, Petr! Now I understand.
    • Edited by SmartWizard Thursday, July 19, 2012 1:28 PM
    •