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#?
The
Lazytype 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 usePublicationOnlyoption 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:Of course, you could turn this code into a
Cacheclass 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).