Klasse in OOP Sprache und Typ

9

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)wo aist ein int und bist ein double" oder
  • "{ (x,y)| xist ein int, yist ein double}"?

Was bedeutet eine Instanz von myclass?

  • " (a,b)wo aist ein int und bist ein double" oder
  • ein Objekt, das einen Speicherplatz einnimmt und das speichern kann (nicht unbedingt, dh leer sein kann) (x,y), wo xist irgendein int und yist irgendein double?
Tim
quelle
2
Eine Klasse ist ein Typ. "{(x, y) | x ist ein beliebiges int, y ist ein beliebiges double}" " wäre fast korrekt, abgesehen von zwei Dingen: 1) Sie haben ein Tupel verwendet, während eine Klasse konzeptionell ein Datensatz ist - Sie beziehen sich auf das Felder nach Namen, nicht nach Position und 2) Nicht jeder Datensatz enthält Felder aund bist Mitglied dieses Typs, wie Killian Forth erwähnt. Myclass ist isomorph zu Datensätzen mit Feldern aund bTyp intund double- Sie könnten einen solchen Datensatz nehmen und in einen solchen umwandeln eine Instanz von myclass.
Doval
1
In stark typisierten Sprachen ist eine Klasse ein Typ. In schwach typisierten Sprachen kann es sich um einen Typ handeln oder nicht.
Shawnhcorey
1
In der Programmiersprachentheorie ist ein Typ eine Menge von Werten? Ich denke, Sie müssen sich ein anderes Buch oder einen anderen Lehrer oder beides besorgen. Eine 'Variable' oder eine 'Konstante' hat einen 'Typ' und oft einen 'Wert'. Es gibt Nullwerttypen, Skalare und zusammengesetzte Werttypen, bei denen der Wert der Variablen oder Konstante Untervariablen / Unterkonstanten enthält.
user1703394
1
@ user1703394 Ein Typ ist eine Reihe von Werten. Ein 32-Bit-Integer-Typ ist eine Menge von 2 ^ 32 verschiedenen Werten. Wenn ein Ausdruck einen Wert dieses Typs ergibt, wissen Sie, dass sich dieser Wert in dieser Menge befindet. Die mathematischen Operatoren sind nur Funktionen über Werten dieser Menge.
Doval
1
Ich wäre auch vorsichtig, wenn ich Typen als Wertesätze betrachten würde. Mengen haben Beziehungen, die nicht unbedingt auf Typen anwendbar sind. Für die Konzeption von Typen ist es ein gutes Modell, aber es bricht zusammen, sobald Sie sich die Dinge genauer ansehen - und sogar mehr, wenn Sie die Untertypisierung einführen.
Telastyn

Antworten:

30

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 CartesianCoordinatesund eine PolarCordinatesKlasse haben, haben beide möglicherweise zwei Zahlen als Felder, und sie haben möglicherweise sogar denselben NumberTyp und dieselben Namen, aber sie sind immer noch nicht kompatibel, und eine Instanz von PolarCoordinateswäre keine Instanz von CartesianCoordinates. 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.

Kilian Foth
quelle
9
Es soll beachtet werden , dass in einigen Sprachen strukturell gleichwertig ist genug , um ein einen Subtyp der anderen Marke Typen (und oft umgekehrt). Das ist jedoch entschieden ungewöhnlich / unbeliebt.
Telastyn
7
@Tim Ein typedef erstellt keinen Typ, sondern alias den Namen, der verwendet wird, um auf einen vorhandenen Typ zu verweisen.
Doval
1
@DevSolar Er erwähnte ausdrücklich C, und außer C ++ kenne ich keine andere Sprache, die dieses Schlüsselwort verwendet.
Doval
3
@ Telastyn - diese Sprachen sollten mit Feuer getötet werden.
Jon Story
4
@ JonStory Die strukturelle Untertypisierung ist auf Modulebene nützlich. Das Fehlen zwingt Sie dazu, alles in interfaceJava 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.
Doval
6

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 NumberTyp oder ähnliches haben, haben sie weder einen EvenNumberTyp, noch wäre es einfach, einen zu erstellen. Ich meine, es ist einfach genug, den Typ selbst zu definieren, aber alle vorhandenen Numbers, die gerade sind, werden nicht auf magische Weise in EvenNumbers 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 typeist typeund objectwird der kanonische Typ als Instanz von angesehen object). 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 Xes sich um einen Subtyp von handelt Y, 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.YX

Kevin
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Weltingenieur
4

Algebraische Datentypen sind der Weg, um dies zu diskutieren.

Es gibt drei grundlegende Möglichkeiten, Typen zu kombinieren:

  • Produkt. Daran denken Sie im Grunde:

    struct IntXDouble{
      int a; 
      double b;
    }
    

    ist ein Produkttyp; seine Werte sind alle möglichen Kombinationen (dh Tupel) von eins intund eins double. 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:

    data IntOrDouble = AnInt Int
                     | ADouble Double
    

    Die Werte dieses Typs haben entweder die Form AnInt 345oder ADouble 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 alle IntWerte auf, jeder muss mit dem AnIntKonstruktor kombiniert werden . Plus , alle DoubleWerte, jeweils kombiniert mit ADouble. 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 structund nicht classfür verwendet IntXDouble. 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 Aund von Bbeiden abgeleitet würde myClass, myClasswäre dies im Wesentlichen die Summe von Aund B. Unabhängig von der tatsächlichen Implementierung.


1 Dies sind Funktionen (im mathematischen Sinne! ); Ein Funktionstyp Int -> Doublewird durch das Exponential dargestellt DoubleInt. Schade, wenn deine Sprache nicht die richtigen Funktionen hat ...

links herum
quelle
2
Entschuldigung, aber ich denke, das ist eine sehr schlechte Antwort. Funktionen tun einen klaren analogen OO, nämlich Verfahren (und Single-Methode Schnittstellentypen). Die grundlegende Definition eines Objekts besteht darin, dass es sowohl den Status (Felder / Datenelemente) als auch das Verhalten (Methoden / Elementfunktionen) aufweist. Ihre Antwort ignoriert letzteres.
Ruakh
@ruakh: nein. Sie können natürlich Funktionen in OO implementieren, aber im Allgemeinen sind Methoden keine Funktionen ( weil sie den Status usw. ändern). Auch "Funktionen" in prozeduralen Sprachen funktionieren nicht. In der Tat kommen Schnittstellen mit einer statischen Methode den Funktions- / Exponentialtypen am nächsten, aber ich hoffte, die Diskussion darüber zu vermeiden, da sie für diese Frage keine Relevanz hat.
links um den
... was noch wichtiger ist , mein anwer tut Verhalten berücksichtigen. In der Tat ist Verhalten normalerweise der Grund, warum Sie Vererbung verwenden, und die Vereinheitlichung verschiedener möglicher Verhaltensweisen erfasst genau den summenartigen Aspekt von OO-Klassen.
links um den
@ruakh Eine Methode kann nicht ohne ihr Objekt. Das nächste Analogon sind staticMethoden, 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.
Doval
@Doval 1) Sie können Methoden um AFAIK herum übergeben, es handelt sich also um erstklassige Werte. 2) Es ist sinnvoll, Funktionen für Gleichheit zu vergleichen, JS-Leute tun es die ganze Zeit.
Den
2

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:

    int areacode;
    int number;

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

DevSolar
quelle
1
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.
Doval
1
Es sei denn, Sie programmieren in Java, wo Sie keine Wahl haben und selbst Ihre dummen No-Behaviour-Faux-Records müssen classes sein. (Das Markieren finalhilft, den Punkt zu vermitteln, aber immer noch). Sie haben jedoch immer noch ein Problem mit protectedMitgliedern, die vererbt werden können und somit Teil einer zweiten API für Implementierer von Unterklassen sind.
Doval
1
@Doval: Ich habe dies als "theoretische" Frage verstanden, weshalb ich mich so weit wie möglich von tatsächlichen Sprachproblemen ferngehalten habe. (Genau wie ich mich so weit protectedwie möglich von Java und in der Praxis
fernhalte ;-)
3
Das Problem ist, dass a classein sprachabhängiges Konstrukt ist. Soweit ich weiß, gibt es keine classTypentheorie.
Doval
1
@Doval: Würde das nicht bedeuten, dass die Typentheorie per se nicht für Klassen gilt, da sie ein Konstrukt außerhalb des Geltungsbereichs dieser Theorie sind?
DevSolar
2
  • 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 intein Typ , hat aber keine Beziehung zu einem interface. Öffentliche / geschützte Feldspezifikationen sind ebenfalls nicht Teil eines interface, 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.

cHao
quelle