OO with rere? how to work-around?

You began this series of postings with a question about emulating OO in ocaml. You indicated in the course of the exchanges that you were interested in the polymorphic aspect of OO rather than with the sub-typing used to achieve it in languages such as C++. In your latest posts you have explored the use of first-class modules to carry out the emulation. (If sub-typing is important to you then you need to look at polymorphic variants and/or ocaml objects/classes.)

OO in the sense to which you have referred requires data and methods to operate on the data. The simplest way to emulate that kind of polymorphic behaviour is with records holding closures, but the closures can equally well be held in a first-class module. Taking the simplest possible example I could envisage, which is the printing of different forms of data polymorphically to the console (below a string and an int, although it could be anything), you end up with something like this:

module type PRINTABLE = sig
  val print : unit -> unit
end

let print_instance (module M : PRINTABLE) =
  M.print ()

let of_string s =
  (module struct
     let print () = print_endline s 
   end : PRINTABLE)

let of_int i =
  (module struct
     let print () = print_int i ; print_newline ()
   end : PRINTABLE)

You wanted to put these polymorphic entities in a list or array, which you can do as follows:

let () =
  List.iter print_instance [ of_string "Hello" ; of_int 42 ]

The problem with this for more complicated situations is that if you have multiple methods for the same data, each method keeps its own copy of the data as a closure. That’s only a pointer but it can add up. There are two common ways to deal with this. The first is to use a wrapper module, to which a convenience ‘make’ function can be added. The following example still only has a single ‘print’ method for the datum ‘self’, but there could be multiple methods:

module type PRINTABLE = sig
  type t
  type u
  val print : t -> unit
  val make: u -> t
end

module type INSTANCE = sig
  module Printable : PRINTABLE
  val self : Printable.t
end
 
let print_instance (module M : INSTANCE) =
  M.Printable.print M.self

module PrintString = struct
  type t = string
  type u = string
  let print s = print_endline s
  let make s = s
end

module PrintInt = struct
  type t = int
  type u = int
  let print i = print_int i ; print_newline ()
  let make i = i
end

let of_string u =
  (module struct
     module Printable = PrintString
     let self = PrintString.make u
   end : INSTANCE)

let of_int u =
  (module struct
     module Printable = PrintInt
     let self = PrintInt.make u
   end : INSTANCE)

let () =
  List.iter print_instance [ of_string "Hello" ; of_int 42 ]

A second way is to use GADTs for the same purpose:

module type PRINTABLE = sig
  type t
  type u
  val print : t -> unit
  val make: u -> t
end

type instance = Instance : (module PRINTABLE with type t = 'a) * 'a
                           -> instance

let print_instance (Instance ((module M), t)) = M.print t

module PrintString = struct
  type t = string
  type u = string
  let print s = print_endline s
  let make s = s
end

module PrintInt = struct
  type t = int
  type u = int
  let print i = print_int i ; print_newline ()
  let make i = i
end

let of_string u =
  Instance ((module PrintString), PrintString.make u)

let of_int u =
  Instance ((module PrintInt), PrintInt.make u)

let () =
  List.iter print_instance [ of_string "Hello" ; of_int 42 ]

I don’t know whether this is exactly what you are looking for - there are many variations on this theme, but I hope it helps.