It is so tiresome to be stupid...

It turns out that if you assign null to your variable and then use it as a reference, the program throws an exception - who would've thought about this :)

Yes, I assigned null to the active variable, not intentionally of course. If only the debugger would have pointed me in the right place....

By on 3/25/2009 9:17 AM ()

Can you post the rest of that class or a small repro?

By on 3/24/2009 7:19 PM ()

Below is a bigger fragment of code. The formatting is messed up though. The external code written in C# calls the GetActiveManager property in the loop, and as I mentioned at first (2 or 3 times) it seems to do what it's supposed to, but then it just blows up with the exception dialog pointing right at the beginning of the lock function. Tomorrow I will try to put together a smaller repro, but for now here it is:

type Manager (filters: Map<string, ISimpleFilter>, tags: Map<string, ITag>, templates: Map<string, ITemplate>, loader: ITemplateLoader) =

let filters = filters

let tags = tags

let templates = templates

let loader = loader

member this.Templates = templates

member this.Filters = filters

member this.Tags = tags

member private this.Loader = loader

static member private lock = new obj()

/// Retrieves the current active template manager

static member GetActiveManager =

lock (lock) (

fun () ->

match !active with

| Some v -> v :?> Manager

| None ->

let m =

new Manager(

Map<string, ISimpleFilter>([]),

Map<string, ITag>([]),

Map<string, ITemplate>([]),

new DefaultLoader())

active := Some (m :> obj)

m

)

By on 3/24/2009 9:32 PM ()

ok, here are my observations/questions:

- what are the first 4 let-bindings for?

- I have a problem with the lock(lock) - it looks like GetActiveManager returns a "() -> Manager" is that right? Why return a function? I guess you want to write "GetActiveManger()" - but then just say "static member GetActiveManager () = ... blablabla" without the fun. Or you might want to put the lock(lock) -statement "in" the returned function - i.e. one line below the "fun() ->" (btw: you don't have to use the "(" ")" bracletes for the lock - just indent the code one more)

- I can't see where you define the active-ref maybe the problem lies with this (the debuger might point you to the lock - but the CLR is not good in debuging anonymous methods so the NullReference might lie inside the returned function instead!)

By on 3/24/2009 10:29 PM ()

- what are the first 4 let-bindings for?

I need them to be able to define the members right below the lets

- I have a problem with the lock(lock) - it looks like GetActiveManager returns a "() -> Manager" is that right? Why return a function?

According to the compiler the return value of the GetActiveManager property is Manager, as intended. It is also confirmed by the fact that first 2 times it did give me my template manager and it did for me exactly what I needed

I guess you want to write "GetActiveManger()" - but then just say "static member GetActiveManager () = ... blablabla" without the fun. Or you might want to put the lock(lock) -statement "in" the returned function - i.e. one line below the "fun() ->" (btw: you don't have to use the "(" ")" bracletes for the lock - just indent the code one more)

- I can't see where you define the active-ref maybe the problem lies with this (the debuger might point you to the lock - but the CLR is not good in debuging anonymous methods so the NullReference might lie inside the returned function instead!)

the active-ref is defined one line up before the type definition with the following statement:

let (active: obj option ref) = ref None

By on 3/25/2009 5:50 AM ()

- what are the first 4 let-bindings for?

I need them to be able to define the members right below the lets

No you don't :) You can use the constructor parameters directly in you code. the compiler will automatically turn them into fields for you. Deleting the four let's in your code should work in exactly the same way.

- I have a problem with the lock(lock) - it looks like GetActiveManager returns a "() -> Manager" is that right? Why return a function?

It's needed for the lock function - it takes an object and a function and then executes the function after taking the lock, and cleaning up after. Similar to the lock statement in C#, but without needing a new keyword. So this code looks correct to me.By the way, you could get rid of the casts by defining active as a Manager option ref type.

By on 3/25/2009 6:41 AM ()

well - sorry about the lock - to my shame(?) I have to admit that I never used lock in F# before.

I thought it's just a languague construct instead of a function.

By on 3/25/2009 10:40 PM ()

You also have "using" (that encapsulates a use expression) that's one of the really nice things about having good support for higher order functions and succintness you can much easier go from encapsulating "object" to the finer grained abstraction of control flow.

By on 3/26/2009 12:18 AM ()

- what are the first 4 let-bindings for?

I need them to be able to define the members right below the lets

No you don't :) You can use the constructor parameters directly in you code. the compiler will automatically turn them into fields for you. Deleting the four let's in your code should work in exactly the same way.

I thougt so too, but the compiler begs to differ. When I tried to remove them it complains about the members referencing the values - or am I missing something here?

- I have a problem with the lock(lock) - it looks like GetActiveManager returns a "() -> Manager" is that right? Why return a function?

It's needed for the lock function - it takes an object and a function and then executes the function after taking the lock, and cleaning up after. Similar to the lock statement in C#, but without needing a new keyword. So this code looks correct to me.

By the way, you could get rid of the casts by defining active as a Manager option ref type.

I would like to, but this would create a circular reference between the variable and the Manager type - right?

By on 3/25/2009 8:08 AM ()

The following compiles for me. Don't know why you can't remove the let bindings - that should work. Right onthe circular reference - the workaround I've used below is to split the type into two parts. Not stellar, but at least it has no runtime overhead. I believe mutually recursive type and let bindings will be addressed in future F# releases.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type Manager (filters: Map<string, string>) =
    member this.Filters = filters
    static member private lock = new obj()

let active: Manager option ref = ref None
    
type Manager with
    /// Retrieves the current active template manager
    static member GetActiveManager = 
        lock (lock) ( 
            fun () -> 
            match !active with 
            | Some v -> v 
            | None -> 
            let m = new Manager(Map<string, string>([]))
            active := Some m
            m
            )

By on 3/25/2009 8:28 AM ()

You can abstract out the Singleton code like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
module Singleton =

    let Create<'a> (init:unit -> 'a) =

        let lockObj = new obj()

        and active : 'a option ref = ref None

        fun () ->

            lock(lockObj) (fun () ->

                match !active with

                | Some x -> x

                | None ->

                    let instance = init()

                    active := Some instance

                    instance)

type Manager (filters: Map<string, ISimpleFilter>, tags: Map<string, ITag>, templates: Map<string, ITemplate>, loader: ITemplateLoader) =

    member this.Templates = templates

    member this.Filters = filters

    member this.Tags = tags

    member private this.Loader = loader

    /// Retrieves the current active template manager

    static member GetActiveManager =

        Singleton.Create (fun () ->

            new Manager(

                Map<string, ISimpleFilter>([]),

                Map<string, ITag>([]),

                Map<string, ITemplate>([]),

                new DefaultLoader()))

My personal oppinion on singletons are that they're a gigantic anti-pattern but if they suite your design at least this way you don't need to re-implement that logic :)

By on 3/25/2009 9:40 AM ()

The following compiles for me. Don't know why you can't remove the let bindings - that should work. Right onthe circular reference - the workaround I've used below is to split the type into two parts. Not stellar, but at least it has no runtime overhead. I believe mutually recursive type and let bindings will be addressed in future F# releases.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type Manager (filters: Map<string, string>) =
  member this.Filters = filters
  static member private lock = new obj()

let active: Manager option ref = ref None
   
type Manager with
  /// Retrieves the current active template manager
  static member GetActiveManager = 
  lock (lock) ( 
  fun () -> 
  match !active with 
  | Some v -> v 
  | None -> 
  let m = new Manager(Map<string, string>([]))
  active := Some m
  m
  )

I tried to remove the lets, and this time around it compiled - go figure

By on 3/25/2009 9:20 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper