In Ocaml habe ich Probleme mit Unterklassen und Typen:
%Vor% Offenbar in Ocaml ist die Klasse sub
nicht ein "Subtyp" der Klasse super
, weil die Methode sub#doIt
eine Methode in sub
aufruft, die in% co_de nicht vorhanden ist %. Dies scheint jedoch ein ziemlich üblicher Anwendungsfall für die OO-Programmierung zu sein. Was ist der empfohlene Weg, dies zu erreichen?
Wie von Rémi erwähnt, besteht das Problem mit Ihrem Code darin, dass das OCaml-Typsystem nur einen Typ pro Ausdruck unterstützt: Ein Ausdruck vom Typ sub
hat nicht den Typ super
. In Ihrem Beispiel erwartet myFunction
ein Argument vom Typ super
, und der Ausdruck new sub
hat den Typ sub
, daher das Problem.
Upcasting ist essentiell für die objektorientierte Programmierung, und OCaml unterstützt es mit zwei verschiedenen Konstrukten.
Der erste ist Typ Zwang . Wenn super
ein Supertyp von sub
ist (dh semantisch verhalten sich Werte vom Typ sub
als Werte von super
) und x : sub
, dann (x :> super) : super
. Der Operator :>
type macht die Konvertierung explizit - das Äquivalent dessen, was populäre objektorientierte Sprachen implizit verwenden, wenn Sie einen Wert vom Typ sub
verwenden, wobei super
erwartet wird.
Der zweite ist Supertyp-Einschränkungen : Erfordert, dass eine gegebene Typvariable ein Subtyp eines bestimmten Typs ist. Dies wird als #super
oder (#super as 'a)
geschrieben, wenn Sie die Typvariable darin benennen möchten. Supertype-Constraints ändern nicht den Typ des Ausdrucks, wie es der Typzwang tut, sie überprüfen lediglich, dass der Typ ein gültiger Subtyp des erforderlichen Typs ist.
Beachten Sie das folgende Beispiel, um sich des Unterschieds bewusst zu werden:
%Vor% Der Typ von pic_smallest_coerce
ist with_size -> with_size -> with_size
: Selbst wenn Sie zwei Instanzen von person
übergeben haben, würde der Rückgabewert den Typ with_size
haben und Sie könnten nicht die Methode name
aufrufen.
Der Typ von pic_smallest_subtype
ist (#with_size as 'a) -> 'a -> 'a
: Wenn Sie zwei Instanzen von person
übergeben, bestimmt das Typsystem 'a = person
und identifiziert den Rückgabewert korrekt vom Typ person
(womit Sie verwenden können die Methode name
).
Kurz gesagt, Supertype-Constraints stellen nur sicher, dass der Code ausgeführt wird, ohne jegliche Informationen zu verlieren - die Variable behält ihren ursprünglichen Typ bei. Typzwang verliert tatsächlich Typinformation (was, ohne Down Casting, sehr unangenehm ist), also sollte nur in zwei Situationen als letzter Ausweg verwendet werden:
1. Sie können keine polymorphe Funktion haben. Bei Supertype-Einschränkungen wird #super
als freie Typvariable verwendet. Wenn Sie also keine freie Typvariable in Ihrem Code verwenden können, müssen Sie darauf verzichten.
2. Sie müssen Werte von verschiedenen tatsächlichen Typen im selben Container speichern. Eine Liste oder eine Referenz, die entweder person
oder box
Instanzen enthalten kann, verwendet with_size
und Zwang:
Beachten Sie, dass der Typ-Inferenz-Algorithmus selbst Supertype-Constraints erkennt (er bestimmt nicht, welche Klasse oder welchen Klassentyp er verwenden wollte, sondern er erstellt einen literalen Klassentyp):
%Vor%Daher ist die Anmerkung zu den eigentlichen Supertype-Einschränkungen nur in Ausnahmefällen nützlich, wenn Sie Ihren Code dokumentieren.
Wenn myFunction
einen Untertyp von super
als Argument akzeptieren soll, sollten Sie es wie folgt definieren:
... oder äquivalent ...
%Vor% Was Ihren Kommentar angeht, scheint sub
in Ihrem Beispiel kein Untertyp von super
zu sein, weil die doIt
-Methode in sub
das ist, was ausgelöst wird, wenn der Objektwert links von #
liegt. Der Operator ist vom Klassentyp sub
, nun, ich denke du täuschst dich. Das ist genau das, was Sie erwarten sollten.
Um Methoden in der Klasse sub
zu erlauben, die Methode doIt
in der Klasse super
aufzurufen, sollten Sie sie wie folgt definieren:
Tags und Links class inheritance object types ocaml