I am facing the issue of implementing a message system between game components in OCaml. The problem here is the Open/Closed principle: I want to be able to create a basic component without specifying all the messages that it can send or receive. In short, I need to write the following in a class:
type message = (* clever definition *)
class abstract component =
object
method virtual react : message
end
And never worry about changing the definition of a message again. Intended behaviour is that bjects can send each other the messages of their choice (I can live with some constraints on what messages actually are, as long as I can create new kinds of messages without altering the above definition). If an object doesn't know how to interpret a message, it raises an exception.
My first approach was to use an exception-throwing approach: a message is fundamentally an unit -> unit function which raises an exception, perhaps with some additional generic information around it (such as the sender). In short:
(* The basic definition *)
type message = unit -> unit
class abstract component =
object
method virtual react : message -> unit
end
(* An example class with a custom message *)
exception MyPrintMessage of string
let myPrintMessage str () -> raise (MyPrintMessage str)
class printer = object
inherit component
method react msg =
try msg () with
| MyPrintMessage s -> Printf.printf "Message: %s\n" s
| n -> raise n
end
(* Sending a message to a 'component' *)
let c =
(new printer) :> component
in
c # react (myPrintMessage "Hello, world!")
The messages are clean, and so is their syntax, and they can also be easily serialized and sent over a network. However, I'm worried about the fact that this isn't very elegant (it's using exceptions at cross-purpose) and might incur performance penalties because of the exception 'walk back up the stack' process.
Any ideas on insights about either this method or an alternate open-closed method?