Why idiomatic F# APIs are good #1

F# OOP code is not the most tidy one on the market, that’s why having an idiomatic F# API gives a .NET library a great advantage. Let’s take a look at how ugly Akka.NET OOP code can be and how clean and nice it becomes being rewritten with Akkling.

Akka.NET stashing actor

type Message =
    | InitializationDone
    | Print of string

type StashingActor() as self =
    inherit UntypedActor()
    
    do self.Become(self.Initializing)
    
    interface IWithUnboundedStash with
        member val Stash = null with get, set

    override this.OnReceive _ = ()
    
    member this.Initializing(msg: obj) : unit =
        match msg with
        | :? Message as msg ->
            match msg with
            | InitializationDone ->
                (this :> IWithUnboundedStash).Stash.UnstashAll()
                this.Become(this.Operating)
            | Print s ->
                printfn "%s stashed" s
                (this :> IWithUnboundedStash).Stash.Stash()
        | _ -> ()
    
    member this.Operating(msg: obj) : unit =
        match msg with
        | :? Message as msg ->
            match msg with
            | Print s -> printfn "Actually printing: %s" s
            | _ -> ()
        | _ -> ()

let system = System.create "test" (Configuration.defaultConfig())
let a = system.ActorOf<StashingActor>()

a.Tell (Print "foo")
a.Tell (Print "bar")
a.Tell InitializationDone
a.Tell (Print "buzz")

Akkling stashing actor

type Message =
    | InitializationDone
    | Print of string

module rec StashingActor =

    let initializing (a: Actor<Message>) = function
        | InitializationDone ->
            a.UnstashAll()
            become (operating a)
        | Print s ->
            printfn "%s stashed" s
            a.Stash() |> ignored

    let operating (a: Actor<Message>) = function
        | Print s -> printfn "Actually printing: %s" s |> ignored
        | _ -> unhandled()

let system = System.create "test" (Configuration.defaultConfig())
let a = spawnAnonymous system (props (actorOf2 StashingActor.initializing)) 

a <! Print "foo"
a <! Print "bar"
a <! InitializationDone
a <! Print "buzz"