Unique compile time id


I have some objects that I want to give a compile time id, something like:

Blah.create ~id:`MyId

I’d like a way to use integers if possible, but have the ergonomics of strings/polymorphic variants. The polymorphic variants seem to pollute the code with a lot of type variables to hold the list of used IDs (I’m not sure of a good way to hide, then compare them?). And I’d like to avoid doing string comparisons between IDs all the time.

Slightly more example code:

type obj1 = <
    id : int; (* Ideally, or something opaque and simple *)
    text : string;

type obj2 = <
    id : int;
    text : string;
    click : unit -> unit;

let obj1 : obj1 = Text.create ~id:`TxtHello ~text:"Hello World" in
let obj2 : obj2 = Button.create ~id:`BtnClick ~text:"Click" ~handler:(fun ...) in

I’d also like to avoid having to pre-allocate a bunch of id’s and avoid having a giant variant with all possible ids. Is there any kind of variant -> int ?

Any ideas?,
Thank you!

Polymorphic variants are represented under the hood as integers:

utop # Obj.is_int (Obj.repr `hello);;
- : bool = true
utop # (Obj.magic `hello : int);;
- : int = 616641298

But, there is no guarantee that they will be unique between different Texts and Buttons.

It’s much less ergonomic, and I’m making this suggestion without full context of what you want to do, but it might be worth taking a look at Base.Type_equal.{Id,Uid}.

I’m surprised there isn’t an obvious way to do this using PPX ?

Ah, that may be all I need! The IDs being global between controls is more or less what I want right now. There’s a later part of the system that erases the specifics with object subtyping, and operates on generic controls, but still needs IDs. The IDs are mostly to say “these are semantically the same element”. There’s a diff between two control layouts and the IDs help track what changed.

No PPX jock I. But I remember there was an example using “getenv”, where the getenv happened at compile-time. I can only imagine that it would be child’s play to concatenate process-id and current-time-in-nanos to get a unique ID, again at compile-time.

I believe this is the ppx_getenv:

I’ll take a look and see how hard it’d be to make something like [%id Blah]. Thanks for the tips!

Oh also, instead of (pid, time-in-nanos), maybe UUIDs instead (e.g. https://github.com/dbuenzli/uuidm ). The C code will guarantee unicity.

Note that objects automatically come with integer identities. That is, you can compare them with = and sort them with <, etc. You can get access to this ID with Oo.id:


utop # let a = object end;;
val a : <  > = <obj>

utop # let b = object end;;
val b : <  > = <obj>

utop # a = a;;
- : bool = true

utop # a = b;;
- : bool = false

utop # Oo.id a;;
- : int = 143

utop # Oo.id b;;
- : int = 145


So you could do e.g.:

let txt_hello = object end;;
let btn_click = object end;;

I suspect OCaml won’t allocate them at compile time, but maybe that doesn’t matter to you (unless it needs to be the same across runs).

1 Like