7
votes

I am building two libraries in OCaml which contain the same variant type. The detail of the variant is not too important, other than that it is really large, and it would be annoying to manually write conversion functions for it. (It's actually the bfd_architecture enumeration converted from C using ocamlidl).

I'm now writing a program using the two libraries. In particular, I'm calling A.f which returns a value of A.variant_type, and I need to use that value in a call to B.g, which takes a value of B.variant_type as an input.

Is there any way to tell OCaml that A.variant_type and B.variant_type are really the same type, and thus it's okay to convert a value from one to the other? The libraries are independent, so they should not reference each other. Right now I'm using Obj.magic to do the conversion, but this is a hack.

3
why can't you, as ygrek suggests, have the two libraries share the same variant type, instead of generating two different variants with the same structure?gasche
In other words, put the variant type into a third module and use it in the others. You can open the module to make the naming more lightweight.Jeffrey Scofield

3 Answers

9
votes

I believe there is no clean way unless these libraries have some common dependency which defines this type (i.e. the same module referenced from both libraries at build time).

4
votes

If you really want the variant type to appear in both libraries, you can also force a check that they are equivalent. In the second library, you can write:

type t = OtherLib.t = | A | B | C | ...

This will make the compiler verify that OtherLib.t = A | B | C | ... and make the two types equal. I don't think it really solves your case, as you probably don't want to change either library.

I usually do that when I want to keep different versions of a type (because they are saved in files that I want to read later), and I want each version to explicit the constructors while keeping the equivalence when possible with the current version.

2
votes

You dont have to use Obj.magic, although you do have to use some "magic",

external convertAB : A.t -> B.t = "%identity"
external convertBA : B.t -> A.t = "%identity"

is enough to do the conversion. Of course, I understand your concern; both types must be exactly the same else you'll be dealing with run-time errors. If it's at all possible and relevant, converting those variants to Polymorphic Variants would solve the problem.