1

I have a problem with rewriting following Akka.Net actor from C# to F#:

public class Listener : ReceiveActor
{
    public Listener()
    {
        Receive<Messages.Shutdown>(s =>
        {
            Console.WriteLine($"shutdown {s.Duration}");
            Context.System.Terminate();
        });
    }
}

Actor should handle only Shutdown message by terminating actor system. I tried to reimplement it like this:

type Listener() =
    inherit ReceiveActor()
    do
        base.Receive<Messages>(fun m -> 
            match m with 
            | Shutdown(duration) -> 
                printf "shutdown %s" (duration.ToString())
                base.Context.System.Terminate()
                true
            | _ -> false)

but there is a complation error in line base.Context.System.Terminate() saying Property 'Context' is static. What is wrong with this code? Why can't I access static property of a baseclass? Is it because this code is in lambda expresion (fun)? Or because it is in constructor (do)?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
GSPdibbler
  • 405
  • 1
  • 9
  • 22
  • 2
    "*Why can't I access static property of a baseclass?*" Who said you couldn't? You just can't access it through an instance – try `ActorBase.Context`... – ildjarn Jun 17 '16 at 19:50

2 Answers2

5

You can write it like this:

type Listener() =
    inherit ReceiveActor()
    do
        base.Receive<Messages>(fun m -> 
            match m with 
            | Shutdown(duration) -> 
                printf "shutdown %s" (duration.ToString())
                ReceiveActor.Context.System.Terminate()
                true
            | _ -> false)

Note that here you can use function instead of match ...with:

        base.Receive<Messages>(function 
            | Shutdown(duration) -> 

Then printfn is the equivalent of WriteLine and this:

printfn "shutdown %s" (duration.ToString())

is the same as:

printfn "shutdown %O" duration

UPDATE

If it is a static property as your error message says, you can't use it from a lambda, for that issue see this already answered question.

Community
  • 1
  • 1
Gus
  • 25,839
  • 2
  • 51
  • 76
  • `ReceiveActor.Context.System.Terminate()` does not work. It gives an error saying that I can not access protected member in lambda expression. – GSPdibbler Jun 17 '16 at 20:44
  • Oh, I didn't know it's protected. Then you can't use the lambda and the ``function`` keyword. The other changes still apply. – Gus Jun 17 '16 at 21:08
4

Figured it out. Problems were:

  1. I used wrong syntax for accessing static member of base class. As @ildjarn commented, it shuld be ReceiveActor.Context, not base.Context.

  2. Protected member cannot be accessed from lambda expression. Handler needs to be a member method.

Working version:

type Listener() as this =
    inherit ReceiveActor()
    do
        base.Receive<Messages>(this.handle)

    member this.handle(message: Messages): bool = 
        match message with 
        | Shutdown(duration) -> 
            printf "shutdown %s" (duration.ToString())
            ReceiveActor.Context.System.Terminate()
            true
        | _ -> false

Important changes: 1. as this lets us call member method from constructor, 2. type annotations in handle method are needed for compiler to resolve Receive method overloading ambiguity.

GSPdibbler
  • 405
  • 1
  • 9
  • 22
  • +1 for figuring out the rest. Have a look at the other details and note that you're still using ``base`` in your code. – Gus Jun 17 '16 at 21:38