The subchapter "20.3.6 Polymorphic variants" describes how to identify polymorphic variant value in C (*It contains a mistake: should be caml_hash_variant
instead of hash_variant
)
I want to use those hash values as error codes in C++ directly. Something like that
archive.mli:
...
type t = ...
type err = [`File_not_found | `Archive_is_corrupted]
val opena : string -> (t, err) error
...
archive.ml
...
let () = Callback.register "open archive" opena
...
archive.cpp:
...
const int Error::File_not_found = caml_hash_variant("File_not_found")
const int Error::Archive_is_corrupted = caml_hash_variant("Archive_is_corrupted")
int Archive::open(char* path) {
static const value* f = nullptr; \
if (f = nullptr)
f = caml_named_value("open archive");
value result = caml_callback(*f, caml_copy_string(path));
if (Tag_val(result) == 0) { // Result.Ok
archive = Field(caml_state, 0);
return ??????
} else { // Result.Error
return Int_val(Field(caml_state, 0));
}
}
...
There is no problem with to return error code and compare it
if (x.open(path) == Error::Archive_is_corrupted) {
...
}
But I don't know what I can return as OK status. 0? -1?
Does any guaranteed value that cannot be returned by caml_hash_variant
exist?
Immediate values in the usual OCaml implementation have the low bit set, and the variant hash is an immediate value. So if you're looking at variant hash values in C++ you can be sure that the value 0 will never be returned by caml_hash_variant.
If you look at the code, the final value is generated either by Val_int() or Val_long(). In the definitions of these macros you'll see that they guarantee that the low bit is set.
I haven't done any kind of analysis of the code, but the value -1 is at least superficially possible as a hash value, since its low bit is set.
Update
The low bit is set on immediate values as a marker for the garbage collector. So it's a convention that must be followed strictly. (IMHO it's one of many really nice design tradeoffs in the OCaml implementation.)