Search code examples
objectpolymorphismocamltyping

Polymorphism typing problems with OCaml objects


On 4.03.0.

I have this code, basically:

module rec First : sig

  type field
  type 'a target = <at_least_this_method: field; .. > as 'a

end = First
and Second : sig

  class foo : object
    method at_least_this_method : First.field
  end

end = Second
and Third : sig

  class usage :
    object

      method action : #Second.foo First.target -> unit

    end

end = struct

  class usage = object
    method action (a : #Second.foo First.target) = ()
  end

end

And the last line of method action fails to type with error message:

Error: Some type variables are unbound in this type:
         class usage :
           object method action : #Second.foo First.target -> unit end
       The method action has type (#Second.foo as 'a) First.target -> unit
       where 'a is unbound

I also tried something like:

  class usage = object
    method action = fun (type t) (b : (#Second.foo as t) First.target) -> ()
  end

But that didn't type either.


Solution

  • EDIT: please refer to @gariguejej's answer below for a better explanation.

    I'm not an expert of type system of objects, but here are my two cents.

    Change your code to:

    module rec First : sig
    
      type field
      type 'a target = <at_least_this_method: field; .. > as 'a
    
    end = First
    and Second : sig
    
      class foo : object
        method at_least_this_method : First.field
      end
    
    end = Second
    
    and Third : sig
    
      class ['a] usage :
        object
          method action : 'a First.target -> unit
        end
    
    end = struct
    
      class ['a] usage = object
        method action : 'a First.target -> unit = fun a -> ()
      end
    
    end
    

    Use ocaml -i, we can see 'a is constrained to constraint 'a = < at_least_this_method : First.field; .. >.

    module rec First :
      sig
        type field
        type 'a target = 'a constraint 'a = < at_least_this_method : field; .. >
      end
    and Second :
      sig class foo : object method at_least_this_method : First.field end end
    and Third :
      sig
        class ['a] usage :
          object
            constraint 'a = < at_least_this_method : First.field; .. >
            method action : 'a First.target -> unit
          end
      end
    

    Of course, you can also manually constraint 'a to <at_least_this_method: field> if you want it to be a closed object type. For example,

    module rec First : sig
    
      type field
      type 'a target = <at_least_this_method: field; .. > as 'a
    
    end = First
    and Second : sig
    
      class foo : object
        method at_least_this_method : First.field
      end
    
    end = Second
    
    and Third : sig
    
      class ['a] usage :
        object
          constraint 'a = <at_least_this_method:First.field>
          method action : 'a First.target -> unit
        end
    
    end = struct
    
      class ['a] usage = object
        constraint 'a = <at_least_this_method:First.field>
        method action : 'a First.target -> unit = fun a -> ()
      end
    
    end
    

    See manual Chapter 3.10