views:

264

answers:

4

I have a cache of data which is getting refreshed from an outside source, and I want to limit my access tot his cache (readonly) inside of my app. I don't want to have refresh the datasource everytime I need access to it (ie. on instantiation go and pull all the data I need, as there is quite a bit of data that is being kept up to date).

type MySingleton = 

        [<DefaultValue>]
        static val mutable private instance: MySingleton

        static member GetInstance() = 
            instance

I guess this is one of the gotchas about implementing a project and trying to learn the language at the same time. I know the logic needs to be

if instance is null
    synchronize
    if instance is null
        instance = new MySingleton()

but the lack of null is throwing me for a loop. I think I can use an option type etc but it is throwing me for a loop

type MySingleton = 

        [<DefaultValue>]
        static val mutable private instance: MySingleton option

        static member GetInstance() = 
            match instance with
                 | Some(i) -> i
                 | None -> 
                            *MySingleton.instance = new MySingleton()
                            MySingleton.instance*

that logic is wrong according to the compiler...

       if Helper.notExists MySingleton.instance then
            MySingleton.instance <- Some(new MySingleton())        
       MySingleton.instance 

should I be using IF statements instead? Is there a prefered pattern for this syntax in f#?

Thank you

+8  A: 

Both .NET 4.0 and F# have Lazy, so I think you want

module MySingleton =
    let private x = Lazy.Create(fun() -> 42)
    let GetInstance() = x.Value

(where 42 might be a new WhateverType() or whatever the expensive initialization is).

http://msdn.microsoft.com/en-us/library/dd997286.aspx

(Commentary: It's 2010, and getting rare to have to explicitly deal with synchronization primitives; languages and libraries are encapsulating all the common patterns.)

Brian
Is there a difference between `Lazy.Create(fun() -> 42)` and `lazy( 42 )` or are those just different syntax for the same thing? If `42` were a constructor call, would it be delayed in both versions?
Joel Mueller
Same thing; lazy(expr) means Lazy.Create(fun()->expr)
Brian
@Brian--isn't basic F# development basically a singleton? I mean seriously--you assign one time and then read from that value over and over again. I'm not sure I understand the difference between this and the singleton pattern.
Onorio Catenacci
@Onorio: The singleton pattern is about two things; having everyone get the same reference to a named object (which is kinda like what you are saying), and avoiding bad side-effects from initialization code (where effects may be actual side-effects, or just 'perf' effects, e.g. something that is slow, or takes up a lot of memory or other resources). You want to ensure that these effects never happen more than once (you only need one object), and that they don't happen unless needed (if no one uses the object, no effects). The lazy initialization buys those effects-guarantees.
Brian
@Brian--ok, I believe I understand what you're saying.
Onorio Catenacci
I ownder how the lazy.create works when interoped with c# - I will need to test that piece out
akaphenom
It's just System.Lazy. http://msdn.microsoft.com/en-us/library/dd642331.aspx
Brian
+1  A: 

The Lazy type as Brian mentioned is a good place to start with. It allows you to ensure that a computation will be run when the value is needed and it guarantees thread safety, meaning that the computation will run only once (although, in some cases, you may also use PublicationOnly option to specify that multiple threads may start to initialize cache and only the first result will be used).

However, you'll probably also need a mechanism for marking the cache as invalid (e.g. after some specified time) and forcing re-initialization of the cache. Note that this isn't really a Singleton pattern. Anyway, you can still do this in a thread safe way using Lazy, but you'll need to structure the code like this:

module Cache = 
  // returns a lazy value that initializes the cache when 
  // accessed for the first time (safely)
  let private createCacheInitialization() = 
    lazy( // some code to calculate cache 
          cache )
  // current cache represented as lazy value
  let private mutable currentCache = createCacheInitialization()

  // Returns the current cache
  let GetCache() = currentCache.Value
  // Reset - cache will be re-initialized next time it is accessed
  // (this doesn't actually initialize a cache - just creates a lazy value)
  let Reset() = currentCache <- createCacheInitialization()

Of course, you could turn this code into a Cache class that takes only the initialization function and encapsulates the rest of the code into a reusable piece (if you need to cache multiple values, for example).

Tomas Petricek
A: 

The original question was "how to implement a Singleton pattern in F#", not "how to implement a Lazy-Load pattern". A singleton is a type that guarantees that there exists exactly one instance of itself overall. Therefore, control over creation of the "one and only" instance must reside completely within the type itself. Using explicit type construction, this is rather difficult to achieve:

/// This type is intended for private use within Singleton only.
type private SyncRoot = private new() = {}

type Singleton =
    // Cannot use implicit ("let"-bound) fields, because the class 
    // is constructed explicitly.
    // --> Must use explicit ("val"-bound) fields. 
    // --> Explicit fields who are static must always be 
    //     default-initialized, mutable, and private.
    [<DefaultValue>] static val mutable private instance: Singleton

    private new() = {}

    static member Instance = 
        let isNull() = 
            Unchecked.compare Singleton.instance Unchecked.defaultof<Singleton> = 0

        if isNull() then
            lock typeof<SyncRoot> (fun() ->
                if isNull() then
                    Singleton.instance <- new Singleton())

        Singleton.instance

However, using implicit type construction, it can be done in a thread-safe way with only few lines of code:

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

Which is the same as:

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

Edit
In the original example, I commented that a primary constructor's accessibility is always the same as the type's accessibility. However, after further experimenting, I finally found out that a primary constructor can have its own access modifier, in addition to the type's access modifier. This was also mentioned in kvb's comment. I therefore revised the example. Unfortunately, this is not documented yet in the F# 2.0 specification, nor in the MSDN documentation. The example presents yet one more reason to prefer implicitly constructed types whenever possible over explicitly constructed ones.

Marc Sigrist
1. You can make a default constructor private (as in, `type PersonSingleton private() = ...`), in which case you can use `static let` within the type. 2. Don't lock on a type instance; because the type is public other code could also lock on it, causing a deadlock.
kvb
+1  A: 

Sorry to reanimate an old question, just wanted to point out that some might try to expose Instance in a public property, in which case the following piece of code might be useful:

type MyType() =
  inherit SomeParent()

  static let mutable instance = lazy(new MyType())
  static member Instance with get() = instance.Value
Dmitri Nesteruk