Sollen Datenstrukturen in die Sprache integriert werden (wie in Python) oder in der Standardbibliothek bereitgestellt werden (wie in Java)?

21

In Python und höchstwahrscheinlich in vielen anderen Programmiersprachen finden sich häufig verwendete Datenstrukturen als integraler Bestandteil der Kernsprache mit einer eigenen dedizierten Syntax. Wenn wir die integrierte Listensyntax von LISP beiseite lassen, kann ich mir keine andere Sprache vorstellen, die eine Art Datenstruktur über dem Array als integrierten Teil ihrer Syntax liefert, obwohl alle von ihnen (aber C, denke ich) scheinen sie in der Standardbibliothek bereitzustellen.

Was halten Sie aus Sicht des Sprachdesigns von einer bestimmten Syntax für Datenstrukturen in der Kernsprache? Ist es eine gute Idee und ändert der Zweck der Sprache (etc.), wie gut dies von einer Wahl sein könnte?

Edit: Es tut mir leid, dass ich (anscheinend) einige Unklarheiten darüber habe, welche Datenstrukturen ich meine. Ich spreche über die grundlegenden und häufig verwendeten, aber immer noch nicht die grundlegendsten. Dies schließt Bäume (zu komplex, ungewöhnlich), Stapel (zu selten verwendet) und Arrays (zu einfach) aus, umfasst jedoch z. B. Mengen, Listen und Hashmaps.

Anto
quelle
1
Schließen wir das Objekt und die Hashmap aus?
Orbling
3
@ Anto: Nun, viele Sprachen haben Hashmaps in Form von assoziativen Arrays, Perl, PHP, JS (technisch ein Objekt hier), etc.
Orbling
1
Vielleicht könnten Sie genauer festlegen, an welche Datenstrukturen Sie denken, abgesehen von Arrays, Listen, Hashmaps / assoziativen Arrays?
FrustratedWithFormsDesigner
1
Schließen Sie Hashmaps, Listen und alles Weiterentwickelte wie die "komplexen Datenstrukturen" ein und werfen Sie Arrays als zu einfach aus.
Anto
1
Ich denke, ein sinnvollerer Titel wäre so etwas wie: "Welche Datenstrukturen sollten in der Sprache enthalten sein und welche in der Bibliothek?" Eine aussagekräftige Antwort hängt jedoch stark von der Sprache ab: Je sauberer die Bibliothek in die Sprache integriert ist, desto sinnvoller ist es, Strukturen in die Bibliothek zu verschieben.
Jerry Coffin

Antworten:

13

Es kommt darauf an, wofür die Sprache ist.

Einige Beispiele (etwas von anderen Antworten gestohlen):

  • Perl hat eine spezielle Syntax für Hashtabellen, Arrays, Strings. Perl wird oft für Skripte verwendet. Diese sind nützlich für Skripte.
  • Matlab hat eine spezielle Syntax für Listen, Matrizen und Strukturen. Matlab dient der Matrix- und Vektormathematik für das Ingenieurwesen.
  • Java / .NET unterstützt Strings und Arrays. Dies sind Allzwecksprachen, in denen häufig Arrays und Zeichenfolgen verwendet werden (immer weniger bei Verwendung neuer Auflistungsklassen).
  • Arrays mit C / C ++ - Unterstützung. Dies sind Sprachen, die Hardware nicht vor Ihnen verbergen. Zeichenfolgen werden teilweise unterstützt (keine Verkettung, Verwendung von strcpy usw.)

Ich denke, es kommt darauf an, was der Zweck / Geist / das Publikum Ihrer Sprache ist. Wie abstrakt und wie weit von der Hardware entfernt soll sie sein? Im Allgemeinen können Sie mit den Sprachen, die Listen als Grundelemente unterstützen, unendlich lange Listen erstellen. Während Low-Level-Versionen wie C / C ++ diese niemals haben würden, ist dies nicht das Ziel, sondern der Geist dieser Sprachen.

Garbage Collection folgt für mich der gleichen Logik: Interessiert es die Zielgruppe Ihrer Sprache, genau zu wissen, wann und ob Speicher zugewiesen oder freigegeben wird? Wenn ja, malloc / free; Wenn nein, dann Müllabfuhr.

ohrenlos
quelle
6
Dies ist ein schlechter Ort, um den Begriff "C / C ++" zu verwenden, da das Vorhandensein von übergeordneten Vorlagentypen in C ++ einen großen Unterschied zwischen den beiden Sprachen darstellt.
Dan04
Garbage Collection kann auf deterministische Weise durchgeführt werden. Sie benötigen lediglich lineare Typen (oder den Ersatz ihres armen Mannes: RAII).
Pyon
@ EduardoLeón, obwohl Sie Garbage Collection an einem deterministischen Punkt aufrufen können, denke ich nicht, wie lange es laufen wird, ist deterministisch (aus dem gleichen Grund, der in C / C ++ mallocund newnicht deterministisch ist).
EarlNameless
@earlNameless: Es ist deterministisch in Bezug auf die Ressourcennutzung: Lineare Typen (oder Eindeutigkeitstypen, die ähnlich sind) machen es zu einem Typfehler (und damit zu einem Kompilierungsfehler), Ressourcen nicht freizugeben (modulo die Möglichkeit, nicht vom Typ erfasst zu werden Programmabbruch) oder zur Verwendung nach deren Entsorgung.
Pyon
5

Perl hat Hashmaps und PL / SQL unterstützt Datensätze, und ich habe sehr trübe Erinnerungen an Matlab mit Syntax zur Unterstützung von Vektoren und Matrizen in allen verschiedenen Dimensionen (obwohl ich mich in dieser Hinsicht irren und argumentieren könnte, dass dies Datentypen und keine Daten sind Strukturen ) ... Ich würde sagen, dass es nett ist, eine native Unterstützung für sehr häufige Strukturen zu haben. Normalerweise scheinen Arrays und Hashmaps / assoziative Arrays die gebräuchlichsten nativ unterstützten Strukturen zu sein, und sie werden wahrscheinlich auch am häufigsten verwendet.

Vergessen Sie nicht, dass, wenn Sie native Syntaxunterstützung für andere Strukturen wie Binärbäume hinzufügen, diese Strukturen auch von den unterstützenden Tools der Sprache (Compiler / Runtime / etc) implementiert wurden. Für wie viele Strukturen möchten Sie Unterstützung aufbauen?

Sie müssen eine neue Notation für die weniger gebräuchlich unterstützten Strukturen erfinden ... Keep It Simple !.

FrustratedWithFormsDesigner
quelle
Es ist nicht nötig, eine wörtliche Syntax für z. B. Bäume zu erfinden - sie sind seltener und nicht einmal in der Standardlib vieler Sprachen enthalten! Mit dem gleichen Argument könnte man die Einbeziehung von Operatoren ablehnen, weil "man für die weniger häufig verwendeten Operationen eine neue Notation erfinden müsste".
@delnan: Ich verstand es aus der Perspektive, eine neue Sprache zu entwerfen und mich zu fragen, ob Datenstrukturen neben Arrays nativ durch (möglicherweise) neue Syntax unterstützt werden sollten oder ob sie durch die Einbindung einer Bibliothek unterstützt werden sollten.
FrustratedWithFormsDesigner
Nun, der erste Satz spricht explizit von "allgemeinen Datenstrukturen", daher gehe ich davon aus, dass OP nicht verrückt genug ist, um für jede obskure Datenstruktur, die jemals erfunden wurde, eine spezielle Syntax hinzuzufügen.
@delnan: ... und dann schließt das OP LISP-Listen und Arrays (im Allgemeinen) aus. "... LISPs integrierte Listensyntax beiseite legen, ich kann mir keine anderen Sprachen vorstellen, die ich kenne Datenstruktur über dem Array als integraler Bestandteil ihrer Syntax "... also dachte ich, sie würden über exotischere Datenstrukturen nachdenken als über Arrays / Listen ...
FrustratedWithFormsDesigner
Ja (ich habe "über den Arrays" als "andere gängige Datenstrukturen" interpretiert), aber nichts in der Frage deutet darauf hin, dass "für jede einzelne Datenstruktur Literale erstellt werden sollen". Es ist in Ordnung zu behaupten, dass dies auf das Vernünftige beschränkt sein sollte, aber ich denke nicht, dass wir "schlechte Idee" nur aufgrund dieser Annahme sagen können .
5

Mein Lieblingsbeispiel hier ist Lua . Lua hat nur einen integrierten Datentyp, die " Tabelle ". Aufgrund ihrer Flexibilität und Geschwindigkeit können Sie sie jedoch anstelle von regulären Arrays, verknüpften Listen, Warteschlangen und Karten verwenden. Sie sind sogar die Grundlage für die objektorientierten Funktionen von Lua (dh Klassen).

Lua ist eine unglaublich einfache Sprache, aber die Flexibilität der Tabellendatenstruktur macht sie auch sehr mächtig.

Dean Harding
quelle
2
JavaScript-Objekte sind genau so - Arrays sind zum Beispiel nur echte Objekte mit numerischen Eigenschaften und einer Länge.
Tikhon Jelvis
1
Lua-Tabellen unterscheiden sich von JavaScript-Objekten: In JavaScript {}ist dies nicht der []Fall, in Lua haben Sie {}für beide. Lua-Tabellen lassen sich besser mit Listen in Lisp vergleichen.
Jakob
Ich vermute in JavaScript, "alles ist ein Objekt" - einschließlich Arrays - aber nicht alles ist ein Array. In Lua ist alles ein Tisch.
Dean Harding
3

Sie müssen nicht für jeden Datentyp auf hoher Ebene eine dedizierte Syntax haben . Zum Beispiel ist es tolerierbar set([1, 2, 3])(wie es Python 2.x getan hat) statt {1, 2, 3}.

Das Wichtigste ist , hat einige bequeme Möglichkeit , eine High-Level - Datenstruktur zu konstruieren. Was Sie vermeiden möchten, ist Code wie:

s = set()
s.add(1)
s.add(2)
s.add(3)

das ärgert mich sehr , wenn ich verwende std::vector, std::setund std::mapin C ++. Zum Glück wird der neue Standard haben std::initializer_list.

dan04
quelle
3

Meiner Meinung nach ist es eine erstaunlich einfache Ergänzung, die überraschend oft nützlich sein kann, zumindest wenn man vorsichtig vorgeht - dh höchstens für Tupel, Listen, Karten und Mengen, die anerkannte Literale haben.

  • Es ist billig, einer Sprache etwas hinzuzufügen. Es kostet Sie nicht viel von diesem kostbaren Komplexitätsbudget:
    • Die Grammatik ist im Grunde someBracket {expr ','} someBracketoder someBracket {expr ':' expr ','} someBracketmit ein paar toten einfachen Extras, wenn Sie Dinge wie optionale Kommas wollen. Die Float-Literale können in der Grammatik leicht länger sein.
    • In vielen Sprachen kollidiert keiner der populären Literale mit der vorhandenen Syntax (eine Ausnahme, die ich mir vorstellen kann, ist eine Sprache mit geschweiften Blöcken als Ausdrücken, einem Kommaoperator und keinem Semikolon wie in {1, 2}).
    • Die Semantik kann in weniger als fünf Sätze, die informelle Version ist definiert werden „Instantiate eine neue $ Sammlung, dann rufen Sie .add/ .append/ .setItemeinmal pro angegebenen Ausdrücke mit diesem (diesen) Ausdruck (s) als Argumente“.
  • Aufgrund des vorherigen dritten Punktes ist es auch sehr einfach zu implementieren.
  • Es ist unglaublich praktisch, wenn Sie eines benötigen, und hat keinen Einfluss auf die Syntax anderer Elemente, dh Sie zahlen nicht dafür, wenn Sie es nicht verwenden.
Mücke
quelle
3

Clojure ist ein lisp aber unterstützt

Lists: (x1 x2)
Vectors: [x1 x2]
Maps: {k1 v1 k2 v2}
Sets: #{x1 x2}
WuHoUnited
quelle
2

Je mehr Datenstrukturen Sie in der Sprache selbst haben, desto schwieriger ist es, die Sprache zu lernen. Es mag eine persönliche Präferenz sein, aber ich bevorzuge eher eine einfachere Sprache, und dann können alle Extras von Bibliotheken bereitgestellt werden.

Sprachen, die für bestimmte Bereiche entwickelt wurden, können manchmal davon profitieren, dass bestimmte Datenstrukturen in die Sprache integriert sind, z. B. Matlab. Aber zu viele können dich überwältigen.

ergodicsum
quelle
2

Damit eine Sprache wirklich nützlich ist, muss sie ein gewisses Maß an Aufgaben von der Stange übernehmen. Weil die praktische tägliche Programmierung Tools erfordert, die ihre Probleme auf einer allgemeinen Ebene lösen. Minimalismus sieht kompakt und cool aus, aber wenn Sie anfangen möchten, große, aber sich wiederholende Probleme zu lösen, benötigen Sie eine Abstraktionsebene, auf der Sie aufbauen können.

Daher denke ich, dass Programmiersprachen Unterstützung für die am häufigsten verwendeten Datenstrukturen in der Syntax für die Aufgaben liefern sollten, für die die Sprache entwickelt wurde.

kamaal
quelle
2

Im Allgemeinen finde ich es praktisch, Literale für Listen, Mengen usw. zu haben. Aber manchmal nervt es mich, dass ich nichts über die tatsächliche Implementierung der Python-Liste oder des Javascript-Arrays weiß. Das Einzige, dessen ich mir sicher sein kann, ist, dass sie eine bestimmte Schnittstelle offen legen.

Ich nehme als Maßstab für die Ausdruckskraft einer Sprache, wie gut sie ihre eigenen Datenstrukturen als Bibliotheken schreiben kann und wie bequem sie zu verwenden ist.

Zum Beispiel bietet Scala verschiedene Kollektionen mit unterschiedlichen Implementierungs- und Leistungsgarantien an. Alle von ihnen sind in Scala selbst implementiert, und die Syntax für ihre Verwendung ist nur geringfügig komplexer als wenn sie eingebaut wären und Laufzeitunterstützung hätten.

Die einzige grundlegende Struktur, die wirklich Unterstützung von der Laufzeit selbst benötigt, zumindest in einer verwalteten Sprache, ist das Array: Wenn Sie den Speicher nicht verwalten, werden Sie Schwierigkeiten haben, eine Reihe benachbarter Bytes zu erhalten. Jede andere Struktur kann aus Arrays und Zeigern (oder Referenzen) aufgebaut werden.

Andrea
quelle
1

APL (und verwandte moderne Varianten, A +, J und K) haben Skalar, Vektor und Matrix als erstklassige Datenstrukturen.

Ja, sie können als reine Array-Varianten verworfen werden. Sie sind aber auch frei von komplexen Deklarationen und stammen nicht aus einer separaten Bibliothek, sondern fühlen sich wie komplexe Datenstrukturen an, die ein erstklassiger Teil der Sprache sind.

S.Lott
quelle
APL hat auch verschachtelte Arrays, und Arrays müssen keinen homogenen Datentyp haben, was allesamt zu sehr leistungsfähigen Datenstrukturen führt.
RFlack
1

Was halten Sie aus Sicht des Sprachdesigns von einer bestimmten Syntax für Datenstrukturen in der Kernsprache? Ist es eine gute Idee und ändert der Zweck der Sprache (etc.), wie gut dies von einer Wahl sein könnte?

Listen- und Map-Literale sowie eine komfortable Abschlusssyntax sind wesentliche Merkmale von Hochsprachen.

Der Unterschied zwischen diesem Java-Code:

Thing t = new Thing();
t.setFoo(3);
t.setBar(6.3);
t.setBaz(true);

und dieser Groovy Code:

t = new Thing(foo: 3, bar: 6.3, baz: true)

ist enorm. Es ist der Unterschied zwischen einem 40.000-Zeilen-Programm und einem 10.000-Zeilen-Programm. Syntax ist wichtig.

Kevin Cline
quelle
In C # kann man: var t = new Thing(foo: 3, bar: 6.3, baz: true);- nur noch 4 Zeichen.
Job
es ist eigentlich die gleiche Nummer; Der Groovy-Code sollte "def t = ..."
lauten
1

Sicher, es hängt von der Anwendung der Programmiersprache ab, aber für höhere Sprachen sollte es so bequem wie möglich sein, mit jeder gängigen Datenstruktur zu arbeiten. Schauen Sie sich beispielsweise die Liste der abstrakten Datentypen in Wikipedia an. Ich fand die folgenden Grundprinzipien am gebräuchlichsten (aber ich möchte auch andere Meinungen hören):

  • geordnete Sequenzen (1-dimensional): Array, Queue, Stack, Listen ...
  • geordnete mehrdimensionale Strukturen : Tabelle, Vektor, Matrix ..
  • Karten : Hashmap, Wörterbuch, Set, Multimap ... (1-dimensional)
  • mehrdimensionale Karten : Funktionen, Karten von Karten ...
  • Diagrammtypen : Bäume, gerichtete Diagramme ...

Sie können jede Struktur mit jeder anderen Struktur emulieren - es kommt nur darauf an, wie einfach und übersichtlich die Programmiersprache dies zulässt. Zum Beispiel:

  • Warteschlange und Stapel können einfach mit Arrays oder Listen emuliert werden. Letztere bieten Operationen wie Push, Pop, Shift usw.
  • geordnete Sequenzen können mit Maps emuliert werden, die numerische Tasten haben
  • Mengen können durch Zuordnungen emuliert werden, die Werte einem Booleschen Wert zuordnen
  • Die meisten Diagrammtypen können durch Verschachtelung von Sequenzen oder Karten emuliert werden
  • Mit Funktionen können Karten emuliert werden, wenn Sie ihre Definition leicht ändern können

Die meisten Sprachen bieten mindestens einen Typ für geordnete Sequenzen, einen für eindimensionale Karten und einen für mehrdimensionale Karten, der auf Funktionen beschränkt ist. Ich persönlich vermisse oft Mengen und geordnete mehrdimensionale Strukturen in Sprachen wie Perl, PHP, JavaScript, Lua ..., weil es nicht bequem genug ist, sie zu emulieren.

Jakob
quelle
1

Ich halte es für eine schlechte Idee, zu viele privilegierte Datentypen mit einer speziellen Syntax zu haben. Dies verkompliziert die Sprachsyntax unnötig, was das Lesen von Code erschwert, Anfängern das Lernen erschwert und die Entwicklung von Tools für die Sprache erschwert.

Es ist in Ordnung, eine Ausnahme für eine kleine Anzahl sehr gebräuchlicher Datenstrukturtypen zu machen. Ich würde wahrscheinlich maximal zulassen:

  • Arrays mit fester Länge
  • Setzt
  • Hashmaps
  • Sequenzen / Listen
  • Datensätze / Strukturen / Klassen

Alles, was raffinierter ist, sollte wahrscheinlich den Bibliotheken überlassen bleiben und die normale Syntax der Sprache für benutzerdefinierte Datentypen verwenden.

Insbesondere haben Dinge wie Rot / Schwarz-Bäume, Prioritätswarteschlangen usw. eine ganze Reihe möglicher Implementierungsoptionen, so dass es nicht ratsam ist, eine bestimmte Implementierung in die Kernsprache zu backen. Es ist besser, die Menschen die für ihre Situation am besten geeignete Implementierung auswählen zu lassen. Beispiele für Implementierungsoptionen, bei denen ich möglicherweise nicht möchte, dass ein Sprachdesigner meine Auswahl einschränkt:

  • Veränderlich oder unveränderlich?
  • Erlaubt Nullen oder nicht?
  • Synchronisiert oder nicht?
  • Durch dauerhaften Speicher gesichert oder nicht?
mikera
quelle