(* Not quite extensible OCaml objects *)
(* Essentially abstract class, or interface *)
class virtual exp = object
method virtual eval : int
end;;
(* `constructor objects' *)
class lit n = object
inherit exp
method eval = n
end;;
class neg e = object
inherit exp
method eval = - e#eval
end;;
class add e1 e2 = object
inherit exp
method eval = e1#eval + e2#eval
end;;
(* A sample expression: like in Haskell, with new *)
let tf1 = new add (new lit 8) (new neg (new add (new lit 1) (new lit 2)));;
let 5 = tf1#eval;;
(* We can easily add another variant: multiplication *)
class mul e1 e2 = object
inherit exp
method eval = e1#eval * e2#eval
end;;
(* Extended sample expressions *)
let tfm1 = new add (new lit 7) (new neg (new mul (new lit 1) (new lit 2)));;
let tfm2 = new mul (new lit 7) tf1;;
let 5 = tfm1#eval;;
let 35 = tfm2#eval;;
(* The expressions are first-class: we can put them into the same list *)
let tl1 = [new lit 1; tf1];;
(* and add the extended objects afterwards *)
let tl2 = tfm1 :: tfm2 :: tl1;;
let [5; 35; 1; 5] = List.map (fun x -> x#eval) tl2;;
(* However, if we want to add another interpreter -- for example, view,
we have to change the class 'exp' to add a new method and change
all children classes lit, neg, add and mul to add a new method view.
All the code that used the old definition has to be revised and
at the very least recompiled.
This is the usual story with objects: they permit extensibility in one
dimension (adding new variants) but not in the other (adding new operations).
*)