Incidentally, the general function for getting a unique integer for a
variant type with non-constant constructors isn't that bad either:
let int_of_gen x =
let x = Obj.repr x
in
if Obj.is_block x
then -1 * Obj.tag x - 1
else (Obj.magic x : int)
I consider that version much better. You could also write it in a more restrictive way :
let to_int x =
let repr = Obj.repr x in
if Obj.is_int repr
then (Obj.obj repr : int)
else invalid_arg "to_int";;
The good point about those is that they check that the memory representation is compatible before casting (while the "%identity" does not). They're safer. Of course, they still break parametricity if used polymorphically, so as you said type should be constrained.
I still would prefer the more direct pattern-matching definition : it may require code generation not to be tedious, but the generated code is an honourable OCaml citizen.