tl; dr: Gibt es eine sprachunabhängige Definition von Symbolen und einen Grund, sie in anderen Sprachen zu haben?
Warum verwendete der Ruby-Schöpfer das Konzept von symbols
in der Sprache?
Ich frage dies aus der Perspektive eines Nicht-Rubin-Programmierers. Ich habe viele andere Sprachen gelernt und in keiner festgestellt, dass ich angeben muss, ob ich mit Ruby zu tun habe oder nicht symbols
.
Die Hauptfrage ist, symbols
ob das Konzept von in Ruby für die Aufführung existiert oder nur etwas, das aufgrund der Art und Weise, wie die Sprache geschrieben ist, benötigt wird.
Wäre ein Programm in Ruby leichter und / oder schneller als das entsprechende Programm in Python oder Javascript? Wenn ja, würde es daran liegen symbols
?
Da es Rubys Absicht ist, für Menschen einfach zu lesen und zu schreiben, konnten die Entwickler den Codierungsprozess nicht vereinfachen, indem sie diese Verbesserungen im Interpreter selbst implementierten (wie es in anderen Sprachen sein könnte)?
Es sieht so aus, als würde jeder nur wissen wollen, was symbols
es ist und wie man es benutzt, und nicht, warum es überhaupt da ist.
quelle
Antworten:
Der Schöpfer von Ruby, Yukihiro "Matz" Matsumoto, hat erklärt, wie Ruby von Lisp, Smalltalk, Perl beeinflusst wurde (und Wikipedia sagt auch Ada und Eiffel):
In jedem Compiler verwalten Sie Bezeichner für Funktionen, Variablen, benannte Blöcke, Typen usw. Normalerweise speichern Sie sie im Compiler und vergessen sie in der erstellten ausführbaren Datei, es sei denn, Sie fügen Debugging-Informationen hinzu.
In Lisp sind solche Symbole erstklassige Ressourcen, die in verschiedenen Paketen gehostet werden. Dies bedeutet, dass Sie zur Laufzeit neue Symbole hinzufügen und diese an verschiedene Arten von Objekten binden können. Dies ist nützlich bei der Metaprogrammierung, da Sie sicher sein können, dass Sie keine Namenskollisionen mit anderen Teilen des Codes haben.
Außerdem werden Symbole zum Zeitpunkt des Lesens interniert und können anhand ihrer Identität verglichen werden. Dies ist ein effizienter Weg, um neue Arten von Werten (wie Zahlen, aber abstrakt) zu erhalten. Mit dieser Hilfe können Sie Code schreiben, in dem Sie symbolische Werte direkt verwenden, anstatt Ihre eigenen Aufzählungstypen mit Ganzzahlen zu definieren. Außerdem kann jedes Symbol zusätzliche Daten enthalten. So kann Emacs / Slime beispielsweise Metadaten aus Emacs direkt in die Eigenschaftsliste eines Symbols einfügen.
Der Begriff des Symbols spielt in Lisp eine zentrale Rolle. Ausführliche Beispiele finden Sie unter PAIP (Paradigmen der Programmierung künstlicher Intelligenz: Fallstudien in Common Lisp, Norvig).
quelle
Nun, sie mussten es nicht unbedingt, sie entschieden sich dafür. Beachten Sie auch, dass
Symbol
s streng genommen nicht Teil der Sprache sind, sondern Teil der Kernbibliothek. Sie haben eine Literal-Syntax auf Sprachebene, aber sie funktionieren genauso gut, wenn Sie sie durch Aufrufen erstellen müsstenSymbol::new
.Sie haben nicht gesagt, was diese "vielen anderen Sprachen" sind, aber hier ist nur ein kleiner Auszug von Sprachen, die einen
Symbol
Datentyp wie Ruby's haben:Es gibt auch andere Sprachen, die die Funktionen von
Symbol
s in einer anderen Form bereitstellen . In Java sind die Funktionen von Ruby'sString
beispielsweise in zwei (tatsächlich drei) Typen unterteilt:String
undStringBuilder
/StringBuffer
. Andererseits werden die Merkmale des Ruby-Symbol
Typs in den Java-String
Typ zusammengefasst: JavaString
kann interniert werden , Literalzeichenfolgen undString
s, die das Ergebnis von zur Kompilierungszeit bewerteten konstanten Ausdrücken sind, werden automatisch interniert, dynamisch erzeugteString
s können durch Aufrufen interniert werden dieString.intern
Methode. Ein InternierterString
in Java ist genau wie ein Internierter inSymbol
Ruby, wird jedoch nicht als separater Typ implementiert, sondern ist nur ein anderer Status als ein JavaString
kann in sein. (Hinweis: In früheren Ruby-Versionen wurde diese MethodeString#to_sym
früher aufgerufenString#intern
und ist heute noch als Legacy-Alias vorhanden.)Symbol
s sind in erster Linie ein Datentyp mit spezifischer Semantik . Diese Semantik ermöglicht es auch, einige performante Operationen (z. B. schnelle O (1) -Gleichheitstests) zu implementieren, aber das ist nicht der Hauptzweck.Symbol
s werden in der Ruby-Sprache überhaupt nicht benötigt, ohne sie würde Ruby problemlos funktionieren. Sie sind eine reine Bibliotheksfunktion. Es gibt genau eine Stelle in der Sprache, die mitSymbol
s verknüpft ist : Eindef
Methodendefinitionsausdruck ergibt einenSymbol
Wert, der den Namen der Methode angibt, die definiert wird. Dies ist jedoch eine relativ neue Änderung. Zuvor wurde der Rückgabewert einfach nicht angegeben. Die MRT-nil
Untersuchung ergab lediglich eine Bewertung , Rubinius eine Bewertung für einRubinius::CompiledMethod
Objekt und so weiter. Es wäre auch möglich, zu einemUnboundMethod
... oder nur zu einem ... zu bewertenString
.Ich bin nicht sicher, was Sie hier fragen. Leistung ist meist eine Frage der Implementierungsqualität, nicht der Sprache. Außerdem ist Node nicht einmal eine Sprache, sondern ein ereignisgesteuertes E / A-Framework für ECMAScript. Durch Ausführen eines entsprechenden Skripts in IronPython und MRI ist IronPython wahrscheinlich schneller. Das Ausführen eines entsprechenden Skripts auf CPython und JRuby + Truffle, JRuby + Truffle ist wahrscheinlich schneller. Dies hat nichts mit
Symbol
s zu tun, sondern mit der Qualität der Implementierung: JRuby + Truffle verfügt über einen aggressiv optimierenden Compiler sowie die gesamte Optimierungsmaschinerie einer leistungsstarken JVM. CPython ist ein einfacher Interpreter.Nr.
Symbol
S sind keine Compiler-Optimierung. Sie sind ein separater Datentyp mit spezifischer Semantik. Sie sind nicht wie die Flonums von YARV , die eine private interne Optimierung fürFloat
s darstellen. Die Situation ist nicht die gleiche wie fürInteger
,Bignum
undFixnum
, was sein soll , eine unsichtbare private interne Optimierung Detail, aber leider ist es nicht. (Dies wird endlich in Ruby 2.4 behoben, das nur entferntFixnum
undBignum
und verlässtInteger
.)Wenn Sie dies wie in Java tun, bedeutet dies,
String
dass Sie als normaler Zustand immer vorsichtig sein müssen, ob sich IhreString
s in diesem speziellen Zustand befinden und unter welchen Umständen sie sich automatisch in diesem speziellen Zustand befinden und wann nicht. Das ist eine viel höhere Belastung als ein separater Datentyp.Symbol
ist ein Datentyp, der das Konzept bezeichnet Namen oder Etikett .Symbol
s sind Wertobjekte , unveränderlich, normalerweise unmittelbar (wenn die Sprache so etwas unterscheidet), staatenlos und haben keine Identität. ZweiSymbol
gleiche sind garantiert auch identisch, dh zweiSymbol
gleiche sind eigentlich dasselbeSymbol
. Dies bedeutet, dass Wertgleichheit und Referenzgleichheit dasselbe sind, und somit ist Gleichheit effizient und O (1).Die Gründe, sie in einer Sprache zu haben, sind wirklich die gleichen, unabhängig von der Sprache. Einige Sprachen stützen sich mehr auf sie als andere.
In der Lisp-Familie gibt es zum Beispiel kein Konzept von "Variable". Stattdessen haben Sie
Symbol
s mit Werten verknüpft.In Sprachen mit reflektierenden oder introspektiven Fähigkeiten,
Symbol
werden s häufig verwendet , um die Namen von reflektiertem Einheiten in dem Reflexions APIs zu bezeichnen, zum Beispiel in Ruby,Object#methods
,Object#singleton_methods
,Object#public_methods
,Object#protected_methods
, undObject#public_methods
eine RückkehrArray
vonSymbol
s (obwohl sie genauso gut könnten eine RückkehrArray
vonMethod
s).Object#public_send
Nimmt eineSymbol
Bezeichnung für den Namen der zu sendenden Nachricht als Argument (obwohl auch eine akzeptiert wirdString
,Symbol
ist dies semantisch korrekter).In ECMAScript sind
Symbol
s ein grundlegender Baustein, um ECMAScript in Zukunft funktionssicher zu machen. Sie spielen auch eine große Rolle bei der Reflexion.quelle
Symbole sind in Ruby nützlich und werden im gesamten Ruby-Code angezeigt, da jedes Symbol bei jedem Verweis wiederverwendet wird. Dies ist eine Leistungsverbesserung gegenüber Zeichenfolgen, da bei jeder Verwendung einer Zeichenfolge, die nicht in einer Variablen gespeichert ist, ein neues Objekt im Speicher erstellt wird. Wenn ich zum Beispiel dieselbe Zeichenfolge mehrmals als Hash-Schlüssel verwende:
Die Zeichenfolge "a" wird 101.000-mal im Speicher erstellt. Wenn ich stattdessen ein Symbol verwendet habe:
Das Symbol
:a
ist immer noch ein Objekt im Speicher. Dies macht Symbole wesentlich effizienter als Zeichenfolgen.UPDATE Hier ist ein Benchmark (entnommen aus der Codecademy ), der den Leistungsunterschied demonstriert:
Hier sind meine Ergebnisse für mein MBP:
Es gibt einen klaren Unterschied zwischen der Verwendung von Zeichenfolgen und Symbolen, um nur die Schlüssel in einem Hash zu identifizieren.
quelle
"a"
in der Tat eine neue Zeichenfolge ist, denke ich, dass es in Ihrem Beispiel genau zwei geben wird"a"
(und eine Implementierung den Speicher sogar teilen könnte, bis eine von ihnen mutiert ist). Um Millionen von Zeichenfolgen zu erstellen, müssten Sie wahrscheinlich String.new ("a") verwenden. Aber ich kenne mich mit Ruby nicht gut aus, also irre ich mich vielleicht.string_AZ[String.new("r")]
um zu sehen, ob das einen Unterschied macht. Ich bekomme 21ms für Strings (Originalversion), 7ms mit Symbolen und 50ms mit jeweils neuen Strings. Daher würde ich sagen, dass Zeichenfolgen in der Literalversion nicht so häufig zugewiesen werden"r"
.