Was ist der richtige Weg, um eine Ocaml-Unterklasse mit zusätzlichen Methoden zu erstellen?

8

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?

    
Dave Rafkind 06.02.2011, 17:07
quelle

3 Antworten

7

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:

%Vor%

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.

    
Victor Nicollet 07.02.2011, 11:09
quelle
8

sub ist wahrscheinlich ein Subtyp von super. Aber in ocaml gibt es keine implizite Typumwandlung. Also deine Funktion akzeptiert keinen Subtyp von Super. Sie müssen explizit einen Zwang ausüben:

%Vor%

Oder akzeptieren Sie vorzugsweise Subtyp von Super:

%Vor%     
Rémi 06.02.2011 18:21
quelle
0

Wenn myFunction einen Untertyp von super als Argument akzeptieren soll, sollten Sie es wie folgt definieren:

%Vor%

... 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:

%Vor%     
james woodyatt 07.02.2011 05:56
quelle