Skip to content

Instantly share code, notes, and snippets.

@Horusiath
Created June 15, 2017 10:35
Show Gist options
  • Save Horusiath/dd83b1fa15335837a4167c43892fa46c to your computer and use it in GitHub Desktop.
Save Horusiath/dd83b1fa15335837a4167c43892fa46c to your computer and use it in GitHub Desktop.
Lack of union types
// we define two message-based protocols: one for data replication one for persistence
// those can be defined easily using discriminated union semantics
type ReplicationProtocol =
| Sync of Endpoint
| ReplicationProgess of ReplicaId * int
| Read of ReplicaId
| ReadRepair of ReplicaId
type PersistenceProtocol =
| Save of PersistenceId * byte[]
| Load of PersistenceId
| Delete of PersistenceId
// now we want to define a state machine able to support i.e. reliable casual broadcast
// for this we need to support both replication and persistence protocols
let agent = Agent.Start(fun mbox ->
let rec loop () = async {
let! msg = mbox.Receive()
// now we hit the wall - we must support both protocols (here described as DUs) however
// we cannot wrap them in any intermediate message (this would result in violation of
// the protocol messages send from elsewhere).
match msg with
| :? ReplicationProtocol rep -> ... // handle replication protocol
| :? PersistenceProtocol per -> ... // handle persistence protocol
}
loop ())
// now an agent is of type Agent<obj> (type being highest common denominator for both DUs), loosing type safety
// with union types we could easily describe it's type as Agent<ReplicationProtocol|PersistenceProtocol>
// keeping it type-safe
@vasily-kirichenko
Copy link

type IProtocol = interface end

type ReplicationProtocol =
    | Sync of Endpoint
    | ReplicationProgess of ReplicaId * int
    | Read of ReplicaId
    | ReadRepair of ReplicaId
    interface IProtocol
  
type PersistenceProtocol = 
    | Save of PersistenceId * byte[]
    | Load of PersistenceId
    | Delete of PersistenceId
    interface IProtocol

let agent = Agent.Start(fun mbox -> 
    async {
        while true do
            let! (msg: IProtocol) = mbox.Receive()
            match msg with
            | :? ReplicationProtocol as rep -> ()
            | :? PersistenceProtocol as per -> ()
            | _ -> failwithf "Unknown protocol %A" msg
    })
  
agent.Post DateTime.Now // does not compile

@Horusiath
Copy link
Author

@vasily-kirichenko What if ReplicationProtocol and PersistenceProtocol live in 2 different assemblies (or even two different projects, one of them being 3rd party lib) with no common dependencies? What when someone has 3rd protocol (i.e. AgentLifecycle) and by mistake pushes it through that agent?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment