OCaml type constructors in C = <unknown constructor>

119 Views Asked by At

I've written some OCaml bindings for some C code; they seem to work fine, except that, at the interpreter, the type constructor appears to be opaque to OCaml. So, for example:

# #load "foo.cma" ;;
# open Foo ;;
# let b = barbie "bar";;
val b : Foo.kung = <unknown constructor>
# let k = ken "kenny" ;;
val k : Foo.tza = <abstr>

I'm trying to get rid of the <unknown constructor> and replace it with a meaningful print.

The contents of foo.ml are:

type kung = Tsau of string [@@boxed] ;;
type tza ;; (* Obviously, an abstract type *)

external barbie : string -> kung = "barbie_doll" ;;
external ken : string -> tza = "ken_doll" ;;

The C code is the minimal amount of code to get this to work:

CAMLprim value barbie(value vstr) { ... }
CAMLprim value ken(value vsttr) { ... }

The actual C code uses caml_alloc_custom() to hold stuff; and obviously has to return what caml_alloc_custom() alloced, so that it doesn't get lost. That's the core reason for using custom types: so I can return the custom malloc's.

Even though these types are abstract or opaque, I'd like to have the let expression print something meaningful. For example, perhaps this?

val b : Foo.kung = "Hi my name is bar"
val k : Foo.tza = "Yo duude it's kenny"

The second question would be: if it's possible to print something meaningful, what should it be? Obviously, the constructors were invoked with strings, so whatever is printed should include those string values...

The third question is: is it possible to specify types and type constructors in C? I suspect that the answer is "obviously no", because OCaml types are static, compile-time types, and are not dynamically constructable. But it never hurts to ask. I mean, the ocaml interpreter is able to deal with brand new type declarations just fine, so somehow, OCaml types aren't entirely static; there's some kind of 'dynamic' aspect to them. I've not found any documentation on this.

1

There are 1 best solutions below

1
Linas On

As suggested in a comment, the answer is to use #install_printer, which is briefly touched on in the toplevel documentation. This is but a hint: example code as follows (keeping with the earlier example).

In foostubs.ml:

(** Signature declarations for C functions *)
external kung_prt : kung -> string = "c_kung_str" ;;

(* Need to #install_printer kung_pretty ;;
 * FYI, the OCaml documentation is confusing
 * as to what a Format.formatter actually is:
 * it is used like a C stream or outport. *)
let kung_pretty : Format.formatter -> kung -> unit =
   function oport ->
      fun x -> Format.fprintf oport "Hi %s" (kung_prt x) ;;

The printer in C would look like this:

CAMLprim value c_kung_str(value vkung)
{
   CAMLparam1(vkung);
   const char* name = String_val(vkung);
   char buff[200];
   strcpy(buff, "my name is ");
   strncat(buff, name, 200);
   CAMLreturn(caml_copy_string(buff));
}

Then, either you have to tell the user to #install_printer kung_pretty ;; or, better yet, provide the user with a setupfoo.ml that does this, and tell them to #use "setupfoo.ml".