class - What's the proper way to make an Ocaml subclass with additional methods? -
in ocaml i'm struggling subclassing , types:
class super = object (self) method doit = ... end; class sub = object (self) inherit super method doit = ... self#somethingelse ... method somethingelse = ... end; let myfunction (s:super) = ... myfunction new sub
apparently in ocaml, class sub
not "subtype" of class super
, because sub#doit
method calls method in sub
not present in super
. however, seems pretty common use-case oo programming. recommended way accomplish this?
as mentioned rémi, problem code ocaml type system supports 1 type per expression: expression of type sub
not of type super
. in example, myfunction
expects argument of type super
, , expression new sub
of type sub
, hence issue.
upcasting essential object-oriented programming, , ocaml support 2 distinct constructs.
the first type coercion. if super
supertype of sub
(meaning semantically, values of type sub
behave values of super
), , x : sub
, (x :> super) : super
. :>
type operator makes conversion explicit — equivalent of popular object-oriented languages implicitly when use avalue of type sub
where super
is expected.
the second supertype constraints: requiring given type variable subtype of given type. written #super
or (#super 'a)
if wish name type variable within. supertype constraints don't change type of expression type coercion does, merely check type valid subtype of required type.
to become more aware of difference, consider following example:
class with_size ~size = object val size = size : int method size = size end class person ~name ~size = object inherit with_size ~size val name = name : string method name = name end let pick_smallest_coerce (a : with_size) (b : with_size) = if # size < b # size else b let pick_smallest_subtype (a : #with_size) (b : #with_size) = if # size < b # size else b
the type of pic_smallest_coerce
with_size -> with_size -> with_size
: if passed 2 person
instances, return value of type with_size
, not able call name
method.
the type of pic_smallest_subtype
(#with_size 'a) -> 'a -> 'a
: if pass 2 person
instances, type system determine 'a = person
, correctly identify return value being of type person
(which lets use name
method).
in short, supertype constraints merely make sure code run, without losing type information @ all — variable retains original type. type coercion loses type information (which, in absence of down-casting, nasty thing), it should used last resort in 2 situations:
1. cannot have polymorphic function. supertype constraints rely on #super
being free type variable, if cannot afford have free type variable in code, have without it.
2. need store values of different actual types in same container. list or reference can contain either person
or box
instances use with_size
, coercion:
let things = [ my_person :> with_size ; my_box :> with_size ]
do note type inference algorithm discover supertype constraints on own (it not determine class or class type intended use, construct literal class type):
let pick_smallest_infer b = if # size < b # size else b val pick_smallest_infer : (< size : 'a ; .. > 'b) -> 'b -> 'b
as such, rare exceptions, annotating actual supertype constraints useful exercise when documenting code.
Comments
Post a Comment