Anfangshinweis:
Diese Frage wurde nach mehreren Änderungen geschlossen, da mir die richtige Terminologie fehlte, um genau zu sagen, wonach ich suchte. Sam Tobin-Hochstadt hat dann einen Kommentar gepostet, der mich genau erkennen ließ, was das war: Programmiersprachen, die Schnittpunkttypen für Funktionsrückgabewerte unterstützen.
Nachdem die Frage erneut geöffnet wurde, habe ich beschlossen, sie zu verbessern, indem ich sie (hoffentlich) genauer umschreibe. Aus diesem Grund sind einige der folgenden Antworten und Kommentare möglicherweise nicht mehr sinnvoll, da sie sich auf frühere Änderungen beziehen. (Bitte lesen Sie in solchen Fällen den Bearbeitungsverlauf der Frage.)
Gibt es beliebte statisch und stark typisierte Programmiersprachen (wie Haskell, generisches Java, C #, F # usw.), die Schnittpunkttypen für Funktionsrückgabewerte unterstützen? Wenn ja, welche und wie?
(Wenn ich ehrlich bin, würde ich wirklich gerne jemanden sehen, der demonstriert, wie Schnittstellentypen in einer gängigen Sprache wie C # oder Java ausgedrückt werden können.)
Ich werde ein kurzes Beispiel dafür geben, wie Schnittpunkttypen mit einem Pseudocode ähnlich C # aussehen könnten:
interface IX { … }
interface IY { … }
interface IB { … }
class A : IX, IY { … }
class B : IX, IY, IB { … }
T fn() where T : IX, IY
{
return … ? new A()
: new B();
}
Das heißt, die Funktion fn
gibt eine Instanz eines Typs zurück T
, von der der Aufrufer nur weiß, dass sie Interfaces IX
und implementiert IY
. (Das heißt, im Gegensatz zu Generika kann der Aufrufer nicht den konkreten Typ auswählen , sondern T
die Funktion. Ich würde davon ausgehen, dass T
es sich in der Tat nicht um einen universellen Typ, sondern um einen existenziellen Typ handelt.)
PS: Mir ist bewusst, dass man einfach eine definieren interface IXY : IX, IY
und den Rückgabetyp von fn
auf ändern könnte IXY
. Dies ist jedoch nicht das gleiche, da Sie eine zusätzliche Schnittstelle häufig nicht IXY
an einen zuvor definierten Typ anschrauben können, A
der nur implementiert IX
und IY
separat ist.
Fußnote: Einige Ressourcen zu Schnittpunkttypen:
Wikipedia-Artikel für "Typensystem" enthält einen Unterabschnitt über Schnittpunkttypen .
Bericht von Benjamin C. Pierce (1991), "Programmieren mit Schnitttypen, Unionstypen und Polymorphismus"
David P. Cunningham (2005), "Intersection types in practice" , der eine Fallstudie über die Forsythe-Sprache enthält, die im Wikipedia-Artikel erwähnt wird.
Eine Stapelüberlauf-Frage, "Verbindungstypen und Kreuzungstypen", die mehrere gute Antworten erhielt, darunter diese, die ein Pseudocode-Beispiel für Kreuzungstypen ähnlich der oben genannten gibt.
T
definiert einen Typ, auch wenn er nur in der Funktionsdeklaration als "ein Typ, der erweitert / implementiertIX
undIY
" definiert ist. Die Tatsache, dass der tatsächliche Rückgabewert ein Sonderfall davon ist (A
bzw. istB
), ist hier nichts Besonderes. Sie können dies auch erreichen, indem SieObject
anstelle von verwendenT
.T
als Schnittstelle behandelt werden,I
wenn alle Methoden der Schnittstelle implementiert werden, diese Schnittstelle wurde jedoch nicht deklariert".Antworten:
In Scala sind vollständige Schnittpunkttypen in die Sprache integriert:
quelle
Tatsächlich lautet die offensichtliche Antwort: Java
Es mag Sie überraschen, zu erfahren, dass Java Kreuzungstypen unterstützt. Dies geschieht in der Tat über den Operator "&". Beispielsweise:
Zeigen Sie diesen Link an mehreren Typgrenzen in Java an, und dies auch über die Java-API.
quelle
<T extends IX & IY> T f() { if(condition) return new A(); else return new B(); }
. Und wie ruft man die Funktion in einem solchen Fall auf? Weder A noch B können am Anrufstandort angezeigt werden, da Sie nicht wissen, welchen Sie erhalten.Ursprüngliche Frage nach "mehrdeutigem Typ" gestellt. Dafür lautete die Antwort:
Mehrdeutiger Typ, offensichtlich keiner. Der Anrufer muss wissen, was er bekommt, also ist das nicht möglich. Alle Sprachen, die zurückgegeben werden können, sind entweder Basistyp, Schnittstelle (möglicherweise automatisch generiert wie im Schnittpunkttyp) oder dynamischer Typ (und dynamischer Typ ist im Grunde nur Typ mit Methoden zum Aufrufen, Abrufen und Festlegen von Namen).
Abgeleitete Schnittstelle:
Sie möchten also im Grunde genommen, dass eine Schnittstelle zurückgegeben wird
IXY
, die abgeleitet wird,IX
undIY
obwohl diese Schnittstelle entweder inA
oder nicht deklariert wurdeB
, möglicherweise, weil sie bei der Definition dieser Typen nicht deklariert wurde. In diesem Fall:A
undB
oder der Schnittpunkt-Typ vonIX
undIY
).PS Eine stark typisierte Sprache ist eine Sprache, in der ein Objekt eines bestimmten Typs nicht als Objekt eines anderen Typs behandelt werden kann, während eine schwach typisierte Sprache eine neu interpretierte Sprache ist. Somit sind alle dynamisch typisierten Sprachen stark typisiert , während schwach typisierte Sprachen Assembler, C und C ++ sind, wobei alle drei statisch typisiert sind .
quelle
Die Art von Go Programming Language hat dies, aber nur für Schnittstellentypen.
In Go implementiert jeder Typ, für den die richtigen Methoden definiert sind, automatisch eine Schnittstelle, sodass der Einwand in Ihrem PS nicht zutrifft. Mit anderen Worten, erstellen Sie einfach eine Schnittstelle, die alle Operationen der zu kombinierenden Schnittstellentypen enthält (für die es eine einfache Syntax gibt), und alles funktioniert.
Ein Beispiel:
quelle
Möglicherweise können Sie tun, was Sie möchten, indem Sie einen begrenzten existenziellen Typ verwenden, der in einer beliebigen Sprache mit Generika und begrenztem Polymorphismus codiert werden kann, z. B. C #.
Der Rückgabetyp ist ungefähr (im Pseudocode)
IAB = exists T. T where T : IA, IB
oder in C #:
Hinweis: Ich habe das nicht getestet.
Der Punkt ist , dass
IAB
in die Lage sein hat eine IABFunc für jeden Rückgabetyp anzuwendenR
, und eineIABFunc
muss Arbeit auf jedem in der Lage sein ,T
die beide SubtypenIA
undIB
.Die Absicht von
DefaultIAB
ist es nur, einen existierendenT
SubtypenIA
und zu verpackenIB
. Beachten Sie, dass dies anders ist als dasIAB : IA, IB
,DefaultIAB
was später immer zu einem bestehenden hinzugefügt werden kannT
.Verweise:
quelle
Apply
auf sie aufgerufen zu werden. Das große Problem ist, dass es keine Möglichkeit gibt, eine anonyme Funktion zum Implementieren einer Schnittstelle zu verwenden. Daher ist die Verwendung von Konstrukten dieser Art ein echtes Problem.TypeScript ist eine weitere typisierte Sprache, die Schnittpunkttypen
T & U
(zusammen mit VereinigungstypenT | U
) unterstützt. Hier ist ein Beispiel aus der Dokumentation zu erweiterten Typen :quelle
Ceylon bietet volle Unterstützung für erstklassige Vereinigungs- und Kreuzungstypen .
Sie schreiben einen Vereinigungstyp als
X | Y
und einen Schnittpunkttyp alsX & Y
.Noch besser ist, dass Ceylon viele raffinierte Überlegungen zu diesen Typen enthält, darunter:
Consumer<X>&Consumer<Y>
derselbe Typ, alsConsumer<X|Y>
ob erConsumer
inX
und kontravariant wäreObject&Null
der gleiche Typ wieNothing
der unterste Typ.quelle
C ++ - Funktionen haben alle einen festen Rückgabetyp, aber wenn sie Zeiger zurückgeben, können die Zeiger mit Einschränkungen auf verschiedene Typen verweisen.
Beispiel:
Das Verhalten des zurückgegebenen Zeigers hängt davon ab, welche
virtual
Funktionen definiert sind, und Sie können beispielsweise mitBase * foo = function(...);dynamic_cast<Derived1>(foo)
.So funktioniert Polymorphismus in C ++.
quelle
any
oder einenvariant
Typ verwenden, wie es der Templates Boost bietet. Somit bleibt die Einschränkung nicht bestehen.class Base1{}; class Base2{}; class Derived1 : public Base1, public Base2 {}; class Derived2 : public Base1, public Base2 {}
... nun, welchen Typ können wir angeben, der die Rückgabe von einemDerived1
oder vonDerived2
keinem zulässtBase1
nochBase2
direkt?Python
Es ist sehr, sehr stark getippt.
Der Typ wird jedoch beim Erstellen einer Funktion nicht deklariert, sodass die zurückgegebenen Objekte "mehrdeutig" sind.
In Ihrer spezifischen Frage könnte ein besserer Begriff "polymorph" sein. Dies ist der gängige Anwendungsfall in Python, bei dem Variantentypen zurückgegeben werden, die eine gemeinsame Schnittstelle implementieren.
Da Python stark typisiert ist, ist das resultierende Objekt eine Instanz von
This
oderThat
und kann nicht (leicht) zu einem anderen Objekttyp gezwungen oder umgewandelt werden.quelle