With the rescript compiler version 8.4.2, the ocaml objects are not available.
Here is a tutorial about how to simulate OO with records.
In Python, the objects are available in the methods as the first parameter usually called "self"
,
so we will re-use this convention to contain the generic data of our objects as a field called .self
in our generic objects implemented with a record.
So here in our type "o"
, we have the field .self
to store the generic data,
one method called .meth
(but you can put several), and a second method called .new_o
to replicate functional update methods of ocaml objects.
type 'a o = { self : 'a; meth : 'a -> int -> int; new_o : 'a -> int -> 'a; }
Here there is a generic type parameter 'a
, if several objects have a different type for the .self field
it will not be possible anymore to store several of these objects in a single structure, like a list for example.
The solution is then to hide the self part by partial application.
Our generic record will then look like this, with no generic type 'a
anymore:
(* our generic object *) type g = { gmeth : int -> int; new_g : int -> g; }
The original type o
has a method .new_o
which returns the new self
element,
which will be used to create the functional update method .new_g
in the generic functional object.
type 'a o = { self : 'a; meth : 'a -> int -> int; new_o : 'a -> int -> 'a; } (* type obj-1 *) let meth1 = (fun a b -> a + b) let new_o1 = (fun a c -> let self = (a + c) in (self) ) let o1 = { self = 5; meth = meth1; new_o = new_o1; } (* type obj-2 *) let meth2 = (fun (a1, a2) b -> a1 + a2 + b) let new_o2 = (fun (a1, a2) c -> let self = (a1 + c, a2 + c) in (self) ) let o2 = { self = (3, 4); meth = meth2; new_o = new_o2; } (* wrap both in obj-g (generic) *) type g = { gmeth : int -> int; new_g : int -> g; } (* hide self by partial application: *) let rec new_g1 self = (fun v -> let self = o1.new_o self v in { gmeth = o1.meth self; new_g = new_g1 self; } ) let g1 = { gmeth = o1.meth o1.self; new_g = new_g1 o1.self; } let rec new_g2 self = (fun v -> let self = o2.new_o self v in { gmeth = o2.meth self; new_g = new_g2 self; } ) let g2 = { gmeth = o2.meth o2.self; new_g = new_g2 o2.self; } (* both objs can now be grouped in a single structure: *) let gs = [ g1; g2; ] ;; let gs = List.map (fun g -> g.new_g 1) gs ;; let () = List.iter (fun g -> Printf.printf "r1:%d\n" (g.gmeth 2)) gs ;; let gs = List.map (fun g -> g.new_g 1) gs ;; let () = List.iter (fun g -> Printf.printf "r2:%d\n" (g.gmeth 2)) gs ;;
The output will be:
r1:8 r1:11 r2:9 r2:13
A generic wrapper function can then be written from the code above, which will
translate every object of type o
into the generic type g
with no 'a
type parameters.
let wrap_g o = let rec new_g self = (fun v -> let self = o.new_o self v in { gmeth = o.meth self; new_g = new_g self; } ) in let g = { gmeth = o.meth o.self; new_g = new_g o.self; } in (g) let g1 = wrap_g o1 let g2 = wrap_g o2 let gs = [ g1; g2; ] ;;