I think you'll need to post your real code. After fixing a few syntax errors, your example code seems to work:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    type Parent<'a>(s) =
       let mutable state = s
       abstract ChangeState : 'a -> bool
       default x.ChangeState(p:'a) = false
       member x.State = state

    type Child(s : int) =
       inherit Parent<int>(s)
       override x.ChangeState p =
          if p > 5 then
             true
          else
             false

    type Client() =
       member x.FixParent (p:Parent<_>) v = p.ChangeState v

    let foo = new Child(23)
    let bar = new Client()
    bar.FixParent foo 39
By on 11/20/2010 7:53 AM ()

Sorry about munging the code from memory last night.

Well I've tried to skinny things down as much as possible here. Hopefully its not too much to digest:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
type ProcessContinuationState =
    | Continue
    | Stop
    | Die


and ProcessMessage<'a> =
    | Execute of ProcessType<'a>


and ProcessType<'a>(state : 'a) =
    let mutable state = state

    abstract member Action : (Computer->ProcessContinuationState)
    default this.Action = (fun c -> Stop)

    member this.State 
        with get() = state
        and set(value) = state <- value


and Computer(id:int) as this =
    let id = id

    do printfn "Created new instance of computer %d" id

    let processQ = MailboxProcessor.Start(fun mbox ->
        let rec processLoop() = async {
            let! msg = mbox.Receive()
            printfn "processQ received a msg"
            match msg with
            | Execute proc ->
                match proc.Action this with
                | Continue ->
                    printfn "Posting next process %A" proc.State
                    mbox.Post(Execute proc)
                    return! processLoop()
                | Stop ->
                    printfn "Finished auto processing"
                    return! processLoop()
                | Die ->
                    printfn "Shutting down processQ"
                    return()
        }
        
        processLoop())

    member this.ID = id
    member this.Exec proc = processQ.Post(Execute proc)


type RepeatingProcess(cycles) =
    inherit ProcessType<int>(cycles)

    override this.Action = (fun (c: Computer) -> 
        printfn "This computer's ID is %d, count %d" c.ID this.State
        Thread.Sleep(250)
        this.State <- this.State - 1
        if this.State > 0 then
            Continue
        else
            Stop)


let comp = new Computer(3)
let rp = new RepeatingProcess(5)
comp.Exec rp
By on 11/20/2010 8:37 AM ()

That code compiles. Can you also post the code that doesn't? :)

By on 11/20/2010 9:25 AM ()

Really?

I copied that directly out of FSI and was getting the type compatibility mismatch. I get the same error when I build in VS2010.

What is your version of F#?

Hmm, this is perplexing. Ok, so this morning when I posted the completed code I was on my desktop machine. The actual code in my F# project is a bit more complicated so I just tried to focus in on the actual work related to the inheritance and invoking the inner processQ. I made the second sample I posted in FSI on my desktop and got the same error regarding the compatibility mismatch that I was getting when I built my project.

After seeing that you got my code sample to work. I tried it on my notebook computer, but just pasting that code into FSI and sure enough it worked. But looking at the code in my actual project and comparing it to the sample it looks exactly the same (except for all the other files and projects referenced). I recompiled the project on my notebook and get the same compatibility mismatch.

I've run into differences between FSI and FSC when running under mono before. But never have noticed a difference when running normally under windows. BTW I'm running Win7 in VMWare Fusion on a Mac (but that shouldn't really make any diff right?).

To give a more complete example I think I'd have to just give you access to the whole project. I have it under SVN at assembla.com. If no one has any better ideas and feels like downloading the whole project I'll post a link to it. To get the whole project to work you'd have to install the powerpack, and probably change the dir paths in the solution.

Derek

By on 11/20/2010 10:43 AM ()

I see, it doesn't work in fsi as separate interactions, but does work from fsc. When I do fsi, the last line yields

Program.fs(58,11): error FS0001: The type 'RepeatingProcess' is not compatible with the type 'ProcessType<obj>'

whereas with fsc, it uses the subsequent context of the upcoming call to define RepeatingProcess as a more specific type.

Lemme take a look now to forumate advice...

By on 11/20/2010 11:19 AM ()

Ok, so I presume you want to be able to process different types of messages on the same computer?

Then do as below. We need a non-generic base type, and I moved the state printing into a ToString override.

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
51
52
53
54
55
56
57
58
59
60
61
62
63
open System.Threading
 
type ProcessContinuationState =
    | Continue
    | Stop
    | Die
 
and ProcessMessage =
    | Execute of ProcessTypeBase
 
and ProcessTypeBase() =
    abstract member Action : (Computer->ProcessContinuationState)
    default this.Action = (fun c -> Stop)
 
and ProcessType<'a>(state : 'a) =
    inherit ProcessTypeBase()
    let mutable state = state
    member this.State 
        with get() = state
        and set(value) = state <- value
    override this.ToString() = sprintf "%A" state
 
and Computer(id:int) as this =
    let id = id
    do printfn "Created new instance of computer %d" id
    let processQ = MailboxProcessor.Start(fun mbox ->
        let rec processLoop() = async {
            let! msg = mbox.Receive()
            printfn "processQ received a msg"
            match msg with
            | Execute proc ->
                match proc.Action this with
                | Continue ->
                    printfn "Posting next process %s" (proc.ToString())
                    mbox.Post(Execute proc)
                    return! processLoop()
                | Stop ->
                    printfn "Finished auto processing"
                    return! processLoop()
                | Die ->
                    printfn "Shutting down processQ"
                    return()
        }
        
        processLoop())
    member this.ID = id
    member this.Exec proc = processQ.Post(Execute proc)
 
type RepeatingProcess(cycles) =
    inherit ProcessType<int>(cycles)
    override this.Action = (fun (c: Computer) -> 
        printfn "This computer's ID is %d, count %d" c.ID this.State
        Thread.Sleep(250)
        this.State <- this.State - 1
        if this.State > 0 then
            Continue
        else
            Stop)
 
let comp = new Computer(3)
let rp = new RepeatingProcess(5)
comp.Exec rp
 
By on 11/20/2010 11:28 AM ()

Yes that is a good idea, except that it denies the processing of the Execute message the ability to directly access proc.State.

Its really troubling to me that my example doesn't compile in fsc, but works fine in fsi. That is the way I really wanted it to work.

Thanks for helping out with this

By on 11/20/2010 11:48 AM ()

You know you're solution is probably fine anyway. I probably never would have needed to use proc.State when processing the Execute method other than for printing out that debug msg.

Do you think that the way I originally tried to do this is wrong, or is there some issue with FSC?

By on 11/20/2010 12:04 PM ()

The original way is wrong; FSC uses the single use of type <int> to fix the thing to only be able to use ints as the states. FSI can't look ahead to see the future use when you send individual interactions, and so without any constraint but a need to pick a concrete type, it generalizes it to <obj>, which is not what you want. Both of those will not provide the flexibility you want. The solution I presented works if you have a second one of type <string> or whatnot, whereas the previous solution would not (in either FSC or FSI). The fact that FSC and FSI treat these differently is kind of a symptom that the thing is not typed the way you want it to be.

By on 11/20/2010 1:23 PM ()
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