In der Programmiersprachentheorie ist ein Typ eine Menge von Werten. Beispielsweise ist der Typ "int" die Menge aller ganzzahligen Werte.
In OOP-Sprachen ist eine Klasse ein Typ, oder?
Wenn eine Klasse mit mehr als einem Mitglied definiert ist, z
class myclass{
int a;
double b;
}
Wenn wir über eine Klasse sprechen, meinen wir das?
- "
(a,b)
woa
ist ein int undb
ist ein double" oder - "{
(x,y)
|x
ist ein int,y
ist ein double}"?
Was bedeutet eine Instanz von myclass
?
- "
(a,b)
woa
ist ein int undb
ist ein double" oder - ein Objekt, das einen Speicherplatz einnimmt und das speichern kann (nicht unbedingt, dh leer sein kann)
(x,y)
, wox
ist irgendein int undy
ist irgendein double?
a
undb
ist Mitglied dieses Typs, wie Killian Forth erwähnt. Myclass ist isomorph zu Datensätzen mit Felderna
undb
Typint
unddouble
- Sie könnten einen solchen Datensatz nehmen und in einen solchen umwandeln eine Instanz vonmyclass
.Antworten:
Weder.
Ich nehme an, Sie fragen sich, ob es ausreicht, denselben Feldtyp zu haben, um ihn als dieselbe Klasse zu klassifizieren, oder ob sie auch identisch benannt werden müssen. Die Antwort lautet: "Es reicht nicht aus, nicht einmal die gleichen Typen und Namen zu haben!" Strukturell äquivalente Klassen sind nicht unbedingt typkompatibel.
Wenn Sie beispielsweise eine
CartesianCoordinates
und einePolarCordinates
Klasse haben, haben beide möglicherweise zwei Zahlen als Felder, und sie haben möglicherweise sogar denselbenNumber
Typ und dieselben Namen, aber sie sind immer noch nicht kompatibel, und eine Instanz vonPolarCoordinates
wäre keine Instanz vonCartesianCoordinates
. Die Möglichkeit, Typen nach ihrem Verwendungszweck und nicht nach ihrer aktuellen Implementierung zu trennen , ist ein sehr nützlicher Teil beim Schreiben von sichererem und wartbarerem Code.quelle
interface
Java und C # umzuwandeln, wenn Sie jemals Unit-Tests durchführen möchten. Am Ende schreiben Sie eine Menge Boilerplate, nur damit Sie die Klasse ändern können, die Ihr Programm verwendet, obwohl Sie nicht beabsichtigen, sie zur Laufzeit zu ändern.Typen sind keine Mengen.
Sie sehen, die Mengenlehre hat eine Reihe von Merkmalen, die einfach nicht für Typen gelten und umgekehrt . Beispielsweise hat ein Objekt einen einzelnen kanonischen Typ. Es kann sich um eine Instanz mehrerer verschiedener Typen handeln, aber nur einer dieser Typen wurde verwendet, um sie zu instanziieren. Die Mengenlehre hat keine Vorstellung von "kanonischen" Mengen.
Mit der Mengenlehre können Sie Teilmengen im laufenden Betrieb erstellen , wenn Sie eine Regel haben, die beschreibt, was zur Teilmenge gehört. Die Typentheorie erlaubt dies im Allgemeinen nicht. Während die meisten Sprachen einen
Number
Typ oder ähnliches haben, haben sie weder einenEvenNumber
Typ, noch wäre es einfach, einen zu erstellen. Ich meine, es ist einfach genug, den Typ selbst zu definieren, aber alle vorhandenenNumber
s, die gerade sind, werden nicht auf magische Weise inEvenNumber
s umgewandelt.Zu sagen, dass Sie Teilmengen "erstellen" können, ist eigentlich etwas unaufrichtig, da Mengen eine ganz andere Art von Tier sind. In der Mengenlehre existieren diese Teilmengen bereits auf alle unendlichen Arten, wie Sie sie definieren können. In der Typentheorie erwarten wir normalerweise, dass es sich zu einem bestimmten Zeitpunkt um eine endliche (wenn auch große) Anzahl von Typen handelt. Die einzigen Typen, die existieren sollen, sind diejenigen, die wir tatsächlich definiert haben, nicht jeder Typ, den wir möglicherweise definieren könnten.
Sets dürfen sich weder direkt noch indirekt enthalten . Einige Sprachen, wie z. B. Python, bieten Typen mit weniger regelmäßigen Strukturen (in Python
type
isttype
undobject
wird der kanonische Typ als Instanz von angesehenobject
). Andererseits erlauben die meisten Sprachen nicht, dass benutzerdefinierte Typen sich auf diese Art von Tricks einlassen.Sätze dürfen sich normalerweise überlappen, ohne ineinander enthalten zu sein. Dies ist in der Typentheorie ungewöhnlich, obwohl einige Sprachen dies in Form einer Mehrfachvererbung unterstützen. Andere Sprachen wie Java erlauben nur eine eingeschränkte Form davon oder verbieten sie vollständig.
Der leere Typ existiert (er wird als unterster Typ bezeichnet ), aber die meisten Sprachen unterstützen ihn nicht oder betrachten ihn nicht als erstklassigen Typ. Der "Typ, der alle anderen Typen enthält" existiert ebenfalls (er wird als Top-Typ bezeichnet ) und wird im Gegensatz zur Mengenlehre weitgehend unterstützt.
NB : Wie einige Kommentatoren bereits erwähnt haben (bevor der Thread in den Chat verschoben wurde), ist es möglich, Typen mit Mengenlehre und anderen mathematischen Standardkonstrukten zu modellieren. Sie können beispielsweise die Typzugehörigkeit als Beziehung modellieren, anstatt Typen als Mengen zu modellieren. In der Praxis ist dies jedoch viel einfacher, wenn Sie die Kategorietheorie anstelle der Mengenlehre verwenden. So modelliert Haskell beispielsweise seine Typentheorie.
Der Begriff "Subtypisierung" unterscheidet sich wirklich stark vom Begriff "Teilmenge". Wenn
X
es sich um einen Subtyp von handeltY
, bedeutet dies, dass wir Instanzen von durch Instanzen von ersetzen können und das Programm in gewissem Sinne immer noch "funktioniert". Dies ist eher verhaltensbezogen als strukturell, obwohl einige Sprachen (z. B. Go, Rust, wohl C) letztere aus Gründen der Benutzerfreundlichkeit entweder für den Programmierer oder für die Sprachimplementierung ausgewählt haben.Y
X
quelle
Algebraische Datentypen sind der Weg, um dies zu diskutieren.
Es gibt drei grundlegende Möglichkeiten, Typen zu kombinieren:
Produkt. Daran denken Sie im Grunde:
ist ein Produkttyp; seine Werte sind alle möglichen Kombinationen (dh Tupel) von eins
int
und einsdouble
. Wenn Sie die Zahlentypen als Mengen betrachten, ist die Kardinalität des Produkttyps tatsächlich das Produkt der Kardinalitäten der Felder.Summe. In prozeduralen Sprachen ist es etwas umständlich, dies direkt auszudrücken (klassisch mit getaggten Gewerkschaften ). Zum besseren Verständnis hier ein Summentyp in Haskell:
Die Werte dieses Typs haben entweder die Form
AnInt 345
oderADouble 4.23
, aber es ist immer nur eine Zahl beteiligt (im Gegensatz zum Produkttyp, bei dem jeder Wert zwei Zahlen hat). Also die Kardinalität: Sie zählen zuerst alleInt
Werte auf, jeder muss mit demAnInt
Konstruktor kombiniert werden . Plus , alleDouble
Werte, jeweils kombiniert mitADouble
. Daher Summentyp .Potenzierung 1 . Ich werde das hier nicht im Detail besprechen, da es überhaupt keine eindeutige OO-Entsprechung gibt.
Was ist also mit dem Unterricht? Ich habe das Schlüsselwort absichtlich
struct
und nichtclass
für verwendetIntXDouble
. Die Sache ist, dass eine Klasse als Typ nicht wirklich durch ihre Felder charakterisiert ist, sondern lediglich Implementierungsdetails. Entscheidend ist vielmehr, welche unterscheidbaren Werte die Klasse haben kann.Was ist relevant ist jedoch, der Wert einer Klasse kann Werte von jedem von den Unterklassen es ! Eine Klasse ist also eher ein Summentyp als ein Produkttyp: Wenn
A
und vonB
beiden abgeleitet würdemyClass
,myClass
wäre dies im Wesentlichen die Summe vonA
undB
. Unabhängig von der tatsächlichen Implementierung.1 Dies sind Funktionen (im mathematischen Sinne! ); Ein Funktionstyp
Int -> Double
wird durch das Exponential dargestelltDouble
Int
. Schade, wenn deine Sprache nicht die richtigen Funktionen hat ...quelle
static
Methoden, außer dass sie immer noch keine erstklassigen Werte sind. Das Besondere an den meisten OO-Sprachen ist, dass sie Objekte als kleinsten Baustein verwenden. Wenn Sie also etwas Kleineres möchten, müssen Sie es mit Objekten fälschen, und am Ende ziehen Sie immer noch eine Reihe von Semantikfunktionen hinein, die Sie nicht haben sollten. Zum Beispiel ist es nicht sinnvoll, Funktionen auf Gleichheit zu vergleichen, aber Sie können trotzdem zwei Faux-Function-Objekte vergleichen.Entschuldigung, aber ich weiß nichts über die "rohe" Theorie. Ich kann nur einen praktischen Ansatz liefern. Ich hoffe, dass dies bei Programmierern akzeptabel ist. Ich bin mit der Etikette hier nicht vertraut.
Ein zentrales Thema von OOP ist das Verstecken von Informationen . Was genau die Datenelemente einer Klasse sind, sollte für ihre Kunden nicht von Interesse sein. Ein Client sendet Nachrichten an eine Instanz (ruft Methoden / Elementfunktionen auf), die den internen Status möglicherweise ändern oder nicht. Die Idee ist, dass sich die Interna einer Klasse ändern können, ohne dass der Client davon betroffen ist.
Eine Entsprechung dazu ist, dass die Klasse dafür verantwortlich ist, dass ihre interne Darstellung "gültig" bleibt. Nehmen wir eine Klasse an, die eine (vereinfachte) Telefonnummer in zwei ganzen Zahlen speichert:
Dies sind die Datenelemente der Klasse. Die Klasse wird jedoch wahrscheinlich viel mehr als nur ihre Datenelemente sein, und sie ist sicherlich nicht als "Menge aller möglichen Werte von int x int" definierbar. Sie sollten keinen direkten Zugriff auf die Datenelemente haben.
Die Konstruktion einer Instanz kann negative Zahlen verweigern. Vielleicht würde die Konstruktion auch die Vorwahl auf irgendeine Weise normalisieren oder sogar die ganze Nummer überprüfen. Sie würden also viel näher an Ihrem sein
"(a,b) where a is an int and b is a double"
, weil es sicherlich keine zwei int sind, die in dieser Klasse gespeichert sind.Aber das ist für die Klasse nicht wirklich wichtig. Es ist weder der Typ der Datenelemente noch der Bereich ihrer möglichen Werte, der die Klasse definiert , sondern die Methoden , die dafür definiert sind.
Solange diese Methoden gleich bleiben, könnte der Implementierer die Datentypen in Gleitkomma, BIGNUMs, Zeichenfolgen usw. ändern, und für alle praktischen Zwecke wäre es immer noch dieselbe Klasse .
Es gibt Entwurfsmuster, um sicherzustellen, dass solche Änderungen der internen Darstellung vorgenommen werden können, ohne dass der Client dies überhaupt bemerkt (z. B. die Pimpl-Sprache in C ++, die alle Datenelemente hinter einem undurchsichtigen Zeiger verbirgt ).
quelle
It is neither the type of the data members, nor the range of their possible values that defines the class, it's the methods that are defined for it.
Die Datenelemente definieren eine Klasse nicht nur, wenn Sie sie ausblenden. Das mag der häufigste Fall sein, aber es kann sicherlich nicht gesagt werden, dass es für alle Klassen gilt. Wenn auch nur ein Feld öffentlich ist, ist es genauso wichtig wie seine Methoden.class
es sein. (Das Markierenfinal
hilft, den Punkt zu vermitteln, aber immer noch). Sie haben jedoch immer noch ein Problem mitprotected
Mitgliedern, die vererbt werden können und somit Teil einer zweiten API für Implementierer von Unterklassen sind.protected
wie möglich von Java und in der Praxisclass
ein sprachabhängiges Konstrukt ist. Soweit ich weiß, gibt es keineclass
Typentheorie.Ein Typ ist eine Beschreibung einer Kategorie / eines Wertebereichs, zusammengesetzter Strukturen oder was Sie haben. OOPwise ähnelt es einer "Schnittstelle". (Im sprachunabhängigen Sinne. Der sprachspezifische Sinn nicht so sehr. In Java ist beispielsweise
int
ein Typ , hat aber keine Beziehung zu eineminterface
. Öffentliche / geschützte Feldspezifikationen sind ebenfalls nicht Teil einesinterface
, sondern ist Teil einer „Schnittstelle“ oder Typ ) .Das Wichtigste ist, dass es viel mehr eine semantische als eine konkrete Definition ist. Die Struktur berücksichtigt nur insofern Faktoren, als die exponierten Felder / Verhaltensweisen und ihre definierten Zwecke übereinstimmen. Wenn Sie nicht beide haben, haben Sie keine Typkompatibilität.
Eine Klasse ist die Verwirklichung eines Typs. Es ist eine Vorlage, die tatsächlich die interne Struktur, das angehängte Verhalten usw. definiert.
quelle