How to define an abstract (opaque) interface for a polymorphic object type?

476 Views Asked by At

ReasonML

module type T = {
  type t('a); // Does not work
  type b; // Works
};

module A: T = {
  type t('a) = {.. b: bool} as 'a;
  type b = bool;
};
module B: T = {
  type t('a) = {.. c: int} as 'a;
  type b = int;
};

Ocaml

module type T  = sig
  type 'a t /* Doesn't work */
  type b /* Works */
end
module A : T = struct type 'a t = < b :bool  ;.. > as 'a
                      type b = bool end 
module B : T = struct type 'a t = < c :int  ;.. > as 'a
                      type b = int end  

How can I define the module type A t('a) so that it is abstract but compatible with the open polymorphic object types in the implementations?

2

There are 2 best solutions below

2
On BEST ANSWER

Types <b : bool; .. > and <c : int; ..> are not compatible much like int and bool are not compatible. In other words, if we will put row polymorphism aside, and focus on simple type constructors, then you're trying to define an interface that matches type int and bool and nothing else, aka bounded polymorphism.

It is also important to understand that subtyping is not inheritance. In your case, you have two classes of objects, the b-class objects that have method b

class virtual b = object
  method virtual b : bool
end

and the c- class of objects that have method c,


class virtual c = object
  method virtual c : int
end

and we can define a class of objects bc that have both methods, naturally via inheritance,

class virtual bc = object
  inherit b
  inherit c
end

Now, let's cooks some objects to play with,

let b : b = object method b = true end
let c : c = object method c = 42 end
let bc : bc = object
  method b = false
  method c = 56
end

We can see that despite that bc class type is defined as inherited from b and c we can't coerce b to c,

# (b : b :> bc);;
Line 1, characters 0-13:
1 | (b : b :> bc);;
    ^^^^^^^^^^^^^
Error: Type b = < b : bool > is not a subtype of bc = < b : bool; c : int > 
       The first object type has no method c

and this makes perfect sense since we're trying to downcast an object of the base class to an object of the derived class, which is an illegal operation. Therefore, when you have a hierarchy of class types ordered by inheritance, the base classes are super types and the derived classes are subtypes. E.g., if v inherits from u then v is a subtype of u,

v inherits-from u
-----------------
   u :> v

Once you get a clear understanding of this, you can design a proper interface.

2
On

It is not clear if it is really useful but you need to add the constraint explicitly in the module type:

module type TA  = sig
  type 'a t constraint 'a = < b:bool; .. >
end
module A : TA = struct
  type 'a t = < b :bool  ;.. > as 'a
end