Struct Embedding in OCaml

OCaml supports modules, which can be used to express a more seamless composition of types. This is similar to the concept of struct embedding in some other languages.

(* Define a base record type *)
type base = { num : int }

(* Define a function for the base type *)
let describe base = 
  Printf.sprintf "base with num=%d" base.num

(* Define a container record type that includes base *)
type container = {
  base : base;
  str : string
}

(* Main function *)
let main () =
  (* Create a container instance *)
  let co = {
    base = { num = 1 };
    str = "some name"
  } in

  (* We can access the base's fields directly on co *)
  Printf.printf "co={num: %d, str: %s}\n" co.base.num co.str;

  (* We can also access the full path using the base field *)
  Printf.printf "also num: %d\n" co.base.num;

  (* We can call the describe function on the base field *)
  Printf.printf "describe: %s\n" (describe co.base);

  (* Define a module signature (similar to an interface) *)
  module type Describer = sig
    val describe : unit -> string
  end;

  (* Create a module that implements the Describer signature *)
  module ContainerDescriber = struct
    let describe () = describe co.base
  end;

  (* Use the module *)
  let module D : Describer = ContainerDescriber in
  Printf.printf "describer: %s\n" (D.describe ())

(* Call the main function *)
let () = main ()

To run the program, save it as struct_composition.ml and use the OCaml compiler:

$ ocamlc -o struct_composition struct_composition.ml
$ ./struct_composition
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

In this OCaml version, we use records to represent structs. The concept of embedding is achieved by including the base record as a field in the container record.

We define functions that operate on these records, similar to methods in object-oriented languages. The describe function is defined for the base type.

To simulate the interface implementation, we use OCaml’s module system. We define a module signature Describer (similar to an interface) and create a module ContainerDescriber that implements this signature.

The main function demonstrates how to create and use these structures, access their fields, and use the module system to achieve polymorphism.

This example showcases OCaml’s powerful type system and module system, which provide ways to achieve composition and polymorphism similar to struct embedding in other languages.