Selbst (Programmiersprache)

Selbst
Logo
Paradigma objektorientierter (Prototypbasiert)
Entworfen von David Ungar, Randall Smith
Entwickler David Ungar, Randall Smith, Universität in Stanford, Sun Microsystems
Erstmals erschienen 1987; vor 35 Jahren
Stabile Version
Mandarin 2017.1 / 24. Mai 2017; vor 5 Jahren
Disziplin tippen dynamisch, stark
Lizenz BSD-ähnliche Lizenz
Webseite www.Selglaus.org
Haupt Implementierungen
Selbst
Beeinflusst von
Smalltalk, Apl[1]
Beeinflusst
NewtonScript, JavaScript, Io, Agora, Quietschen, Lua, Faktor, Rebol

Self ist ein Objekt orientierte Programmierung Sprache basierend auf dem Konzept von Prototypen. Selbst begann als Dialekt von Smalltalk, Sein dynamisch getippt und verwenden Just-in-Time-Zusammenstellung (JIT) sowie der prototypbasierte Ansatz für Objekte: Es wurde zunächst als experimentelles Testsystem für das Sprachdesign in den 1980er und 1990er Jahren verwendet. Im Jahr 2006 wurde Self immer noch als Teil des Klein -Projekts entwickelt, das eine selbst virtuelle Maschine war, die vollständig in sich selbst geschrieben wurde. Die neueste Version ist 2017.1 im Mai 2017 veröffentlicht.[2]

Mehrere Just-in-Time-Kompilierungstechniken wurden in der Selbstforschung Pionierarbeit und verbessert, da sie erforderlich mussten, um eine sehr hohe objektorientierte Sprache zu ermöglichen, um bis zu der Hälfte der Geschwindigkeit des optimierten C-Tats Sun Microsystemsund die Techniken, die sie entwickelten, wurden später eingesetzt Java's Hotspot virtuelle Maschine.

Irgendwann wurde eine Version von SmallTalk in sich selbst implementiert. Da es in der Lage war, die JIT zu verwenden, gab dies auch eine extrem gute Leistung.[3]

Geschichte

Selbst wurde hauptsächlich von entworfen David Ungar und Randall Smith im Jahr 1986 bei der Arbeit bei Xerox Parc. Ihr Ziel war es, den Stand der Technik in objektorientierter Programmiersprachenforschung einmal voranzutreiben Smalltalk-80 wurde von den Labors freigelassen und begann von der Branche ernst genommen zu werden. Sie zogen zu Universität in Stanford und fuhr fort, an der Sprache zu arbeiten und 1987 den ersten funktionierenden Selbst Compiler aufzubauen. Zu diesem Zeitpunkt änderte sich der Fokus auf den Versuch, ein ganzes System für sich selbst zu erzählen, im Gegensatz zu der Sprache.

Die erste Veröffentlichung war 1990 und im nächsten Jahr zog das Team um Sun Microsystems wo sie weiter an der Sprache arbeiteten. Es folgten mehrere Neuveröffentlichungen, bis 1995 mit der 4.0 -Version weitgehend ruhte. Die 4.3 -Version wurde 2006 veröffentlicht und lief weiter Mac OS X und Solaris. Eine neue Veröffentlichung im Jahr 2010,[4] Version 4.4 wurde von einer Gruppe entwickelt, die einige der ursprünglichen Team- und unabhängigen Programmierer umfasst und für Mac OS X und für Mac OS X und verfügbar ist Linuxwie alle folgenden Versionen. Das Follow-up 4.5 wurde im Januar 2014 veröffentlicht.[5] Und drei Jahre später wurde die Version 2017.1 im Mai 2017 veröffentlicht.

Selbst inspirierte auch eine Reihe von Sprachen, die auf seinen Konzepten basierten. Am bemerkenswertesten waren vielleicht vielleicht NewtonScript für die Apple Newton und JavaScript in allen modernen Browsern verwendet. Andere Beispiele sind Io, Lisaac und Agora. Das verteilte Objektsystem des IBM Tivoli Framework, das 1990 entwickelt wurde, war auf der niedrigsten Ebene ein von sich selbst inspiriertes prototypbasiertes Objektsystem.

Prototypbasierte Programmiersprachen

Traditionelle klassenbasierte OO-Sprachen basieren auf einer tief verwurzelten Dualität:

  1. Klassen Definieren Sie die Grundqualitäten und Verhaltensweisen von Objekten.
  2. Objektinstanzen sind besondere Manifestationen einer Klasse.

Nehmen Sie zum Beispiel Objekte der Fahrzeug Klasse haben a Name und die Fähigkeit, verschiedene Aktionen auszuführen, wie z. zur Arbeit fahren und Liefern Sie Baumaterialien. Bobs Auto ist ein bestimmtes Objekt (Instanz) der Klasse Fahrzeug, mit dem Namen "Bobs Auto". Theoretisch kann man dann eine Nachricht an senden Bobs Auto, es zu erzählen Liefern Sie Baumaterialien.

Dieses Beispiel zeigt eines der Probleme mit diesem Ansatz: Bobs Auto, das zufällig ein Sportwagen ist, ist nicht in der Lage, Baumaterialien zu tragen und zu liefern (in jedem sinnvollen Sinne), aber dies ist eine Fähigkeit, die Fahrzeugs sind modelliert zu haben. Ein nützlicheres Modell ergibt sich aus der Verwendung von Unterklasse Spezialisierungen von zu schaffen von Fahrzeug; zum Beispiel Sportwagen und Flachbett-LKW. Nur Objekte der Klasse Flachbett-LKW brauchen einen Mechanismus für Liefern Sie Baumaterialien; Sportwagen, die für diese Art von Arbeit schlecht geeignet sind, brauchen nur für diese Art von Arbeit schnell fahren. Dieses tiefere Modell erfordert jedoch mehr Einblicke während des Designs, ein Einblick, der nur dann ans Licht kommt, wenn Probleme auftreten.

Dieses Problem ist einer der motivierenden Faktoren dahinter Prototypen. Wenn man nicht mit Sicherheit vorhersagen kann, welche Eigenschaften eine Reihe von Objekten und Klassen in der fernen Zukunft haben werden, kann man eine Klassenhierarchie nicht richtig entwerfen. Allzu oft müsste das Programm irgendwann zusätzliches Verhalten benötigen, und Abschnitte des Systems müssten neu gestaltet werden (oder refaktiert) die Objekte auf andere Weise ausbrechen. Erfahrung mit frühen OO -Sprachen wie Smalltalk zeigte, dass diese Art von Problem immer wieder auftauchte. Systeme wachsen tendenziell bis zu einem Punkt und werden dann sehr starr, da die grundlegenden Klassen tief unter dem Code des Programmierers einfach "falsch" wurden. Ohne eine Möglichkeit, die ursprüngliche Klasse leicht zu ändern, können ernsthafte Probleme auftreten.

Dynamische Sprachen wie SmallTalk ermöglichten diese Art von Veränderung durch bekannte Methoden in den Klassen; Durch das Ändern der Klasse würden die darauf basierenden Objekte ihr Verhalten ändern. Solche Änderungen mussten jedoch sehr sorgfältig vorgenommen werden, da andere Objekte, die auf derselben Klasse basieren, dieses "falsche" Verhalten erwarten könnten: "Falsch" hängt oft vom Kontext ab. (Dies ist eine Form der Fragile Basisklassenproblem.) Ferner in Sprachen wie C ++, wo Unterklassen getrennt von Superklassen zusammengestellt werden können, kann eine Änderung einer Superklasse tatsächlich vorkompilierte Unterklassenmethoden brechen. (Dies ist eine andere Form des fragilen Basisklassenproblems und auch eine Form der Fragile Binärschnittstellenproblem.))

In sich selbst und anderen prototypbasierten Sprachen wird die Dualität zwischen Klassen und Objektinstanzen beseitigt.

Anstatt eine "Instanz" eines Objekts zu haben, das auf einer "Klasse" basiert, macht man in sich selbst eine Kopie eines vorhandenen Objekts und ändert es. So Bobs Auto würde erstellt, indem eine Kopie eines vorhandenen "Fahrzeugs" -Objekts erstellt und dann das hinzugefügt wird schnell fahren Methode, Modellierung der Tatsache, dass es zufällig ist Porsche 911. Grundlegende Objekte, die hauptsächlich verwendet werden, um Kopien zu erstellen, werden als bezeichnet als Prototypen. Diese Technik soll die Dynamik stark vereinfachen. Wenn sich ein vorhandenes Objekt (oder eine Reihe von Objekten) als unzureichendes Modell erweist, kann ein Programmierer einfach ein modifiziertes Objekt mit dem richtigen Verhalten erstellen und dies stattdessen verwenden. Code, der die vorhandenen Objekte verwendet, wird nicht geändert.

Beschreibung

Selbstobjekte sind eine Sammlung von "Slots". Slots sind Accessor -Methoden, die Werte zurückgeben, und ein Dickdarm nach dem Namen eines Steckplatzes legt den Wert fest. Zum Beispiel für einen Slot namens "Name",

meine Person Name 

Gibt den Wert im Namen und den Wert zurück, und

meine Person Name:"Foo" 

setzt es.

Selbst, wie SmallTalk, verwendet Blöcke für Flusskontrolle und andere Aufgaben. Methoden sind Objekte, die zusätzlich zu Slots (die sie für Argumente und temporäre Werte verwenden) Code enthalten und können wie jedes andere Objekt in einen Selbstschlitz platziert werden: eine Nummer zum Beispiel. Die Syntax bleibt in beiden Fällen gleich.

Beachten Sie, dass zwischen Feldern und Methoden keine Unterscheidung in sich selbst besteht: Alles ist ein Slot. Da der Zugriff auf Slots über Nachrichten die Mehrheit der Syntax in sich selbst bildet, werden viele Nachrichten an "Selbst" gesendet, und das "Selbst" kann aufgehalten werden (daher der Name).

Grundlegende Syntax

Die Syntax für den Zugriff auf Slots ähnelt der von SmallTalk. Drei Arten von Nachrichten sind verfügbar:

einstellig
Receiver Slot_Name
binär
Empfänger + Argument
Stichwort
Empfängerschlüsselwort: arg1 mit: arg2

Alle Nachrichten geben Ergebnisse zurück, sodass der Empfänger (falls vorhanden) und Argumente selbst das Ergebnis anderer Nachrichten sein können. Das Befolgen einer Nachricht mit einem Zeitraum bedeutet, dass Selbst den zurückgegebenen Wert verworfen. Zum Beispiel:

'Hallo Welt!' drucken. 

Dies ist die Selbstversion der Hallo Welt Programm. Das ' Die Syntax zeigt ein wörtliches String -Objekt an. Andere Literale umfassen Zahlen, Blöcke und allgemeine Objekte.

Die Gruppierung kann durch Verwendung von Klammern erzwungen werden. In Ermangelung einer expliziten Gruppierung wird angesehen, dass die Unary -Nachrichten die höchste Vorrang haben, gefolgt von Binärdateien (Gruppierung von links nach rechts) und den Schlüsselwörtern mit den niedrigsten. Die Verwendung von Schlüsselwörtern für die Zuordnung würde zu einer zusätzlichen Klammung führen, bei der Ausdrücke auch Schlüsselwortmeldungen hatten. Um zu vermeiden, dass das Selbst den ersten Teil eines Keyword -Nachrichtenauswahl mit einem Kleinbuchstaben startet und nachfolgende Teile mit einem Großbuchstaben beginnen.

gültig: Base Unterseite  zwischen: Ligatur Unterseite + Höhe  Und: Base oben / Skala Faktor. 

kann eindeutig analysiert werden und bedeutet das Gleiche wie:

gültig: ((Base Unterseite)) zwischen: ((Ligatur Unterseite) + Höhe)) Und: ((Base oben) / (Skala Faktor))). 

In SmallTalk-80 würde der gleiche Ausdruck geschrieben aussehen wie:

gültig : = selbst Base Unterseite  zwischen: selbst Ligatur Unterseite + selbst Höhe  und: selbst Base oben / selbst Skala Faktor. 

Annahme Base, Ligatur, Höhe und Skala waren nicht Instanzvariablen von selbst waren aber in der Tat Methoden.

Neue Objekte machen

Betrachten Sie ein etwas komplexeres Beispiel:

LabelWidget Kopieren Etikett: 'Hallo Welt!'. 

Erstellt eine Kopie des "LabelWidget" -Objekts mit der Kopiernachricht (keine Verknüpfung diesmal) und sendet ihm dann eine Nachricht, um "Hallo, Welt" in den Steckplatz "Label" zu geben. Nun, um etwas damit zu tun:

(Desktop ActiveWindow) zeichnen: (LabelWidget Kopieren Etikett: 'Hallo Welt!'). 

In diesem Fall der (Desktop ActiveWindow) wird zuerst durchgeführt, um die zurückzugeben Aktives Fenster Aus der Liste der Windows, von denen das Desktop -Objekt weiß. Als nächstes gibt der Code, den wir zuvor untersucht haben, das LabelWidget zurück. Schließlich wird das Widget in den Draw Slot des aktiven Fensters geschickt.

Delegation

Theoretisch ist jedes Selbstobjekt eine eigenständige Einheit. Selbst hat weder Klassen noch Metaklassen. Änderungen an einem bestimmten Objekt betreffen keine anderen, aber in einigen Fällen ist es wünschenswert, wenn dies der Fall ist. Normalerweise kann ein Objekt nur Nachrichten verstehen, die seinen lokalen Slots entsprechen, aber ein oder mehrere Slots anzeigen Elternteil Objekte, ein Objekt kann delegieren Jede Nachricht, die sich nicht mit dem übergeordneten Objekt versteht. Jeder Steckplatz kann zu einem übergeordneten Zeiger hergestellt werden, indem ein Stern als Suffix hinzugefügt wird. Auf diese Weise übernimmt Selbstvertreter die Pflichten, die verwendet werden würden Nachlass in klassenbasierten Sprachen. Die Delegation kann auch verwendet werden, um Funktionen wie z. Namespaces und lexikaler Scoping.

Angenommen, ein Objekt wird als "Bankkonto" definiert, das in einer einfachen Buchhaltung verwendet wird. Normalerweise würde dieses Objekt mit den Methoden im Inneren, möglicherweise "Einzahlung" und "zurückziehen" und alle von ihnen benötigten Datensteckplätze erstellt. Dies ist ein Prototyp, der nur in der Art und Weise, wie er verwendet wird, speziell ist, da er auch ein voll funktionsfähiges Bankkonto ist.

Züge

Das Erstellen eines Klons dieses Objekts für "Bobs Konto" erstellt ein neues Objekt, das genau wie der Prototyp beginnt. In diesem Fall haben wir die Slots einschließlich der Methoden und alle Daten kopiert. Eine häufigere Lösung besteht jedoch darin, zunächst ein einfacheres Objekt zu erstellen, das als a genannt wird Merkmale Objekt Das enthält die Elemente, die man normalerweise mit einer Klasse assoziieren würde.

In diesem Beispiel hätte das "Bankkonto" -Objekt nicht die Einzahlungs- und Abhebungsmethode, sondern als Elternteil ein Objekt, das dies getan hat. Auf diese Weise können viele Kopien des Bankkontosobjekts erstellt werden, aber wir können das Verhalten von allen ändern, indem wir die Slots in diesem Wurzelobjekt ändern.

Wie unterscheidet sich das von einer traditionellen Klasse? Betrachten Sie die Bedeutung von:

myObject Elternteil: Eintuchs. 

Dieser Auszug ändert die "Klasse" von MyObject zur Laufzeit, indem der mit dem 'übergeordnete*' Slot verknüpfte Wert geändert wird (der Stern ist Teil des Steckplatznamens, nicht jedoch der entsprechenden Nachrichten). Im Gegensatz zu Vererbung oder lexikalischer Scoping kann das Delegate -Objekt zur Laufzeit geändert werden.

Hinzufügen von Slots

Objekte in sich selbst können so geändert werden, dass sie zusätzliche Slots enthalten. Dies kann unter Verwendung der grafischen Programmierumgebung oder mit den primitiven '_addslots:' erfolgen. EIN Primitive Hat die gleiche Syntax wie eine normale Schlüsselwortmeldung, aber der Name beginnt mit dem Unterstrich. Die primitiven _addslots sollten vermieden werden, da es aus frühen Implementierungen übrig ist. Wir werden es jedoch im folgenden Beispiel zeigen, da der Code kürzer wird.

In einem früheren Beispiel ging es darum, eine einfache Klasse namens Vehicle neu zu gestalten, um das Verhalten zwischen Autos und Lastwagen unterscheiden zu können. In sich selbst würde man dies mit so etwas erreichen:

_Fügt hinzu: (| Fahrzeug <- (|Elternteil* = Züge klonbar |) |). 

Da der Empfänger der '_addsLots:' Primitive nicht angezeigt ist, ist es "Selbst". Bei Ausdrücken, die an der Eingabeaufforderung tippt werden, ist dies ein Objekt, das als "Lobby" bezeichnet wird. Das Argument für '_Addslots:' ist das Objekt, dessen Slots an den Empfänger kopiert werden. In diesem Fall handelt es sich um ein wörtliches Objekt mit genau einem Slot. Der Name des Steckplatzes lautet "Fahrzeug" und sein Wert ist ein weiteres wörtliches Objekt. Die "<-" Notation impliziert einen zweiten Steckplatz namens "Vehikel", mit dem der Wert des ersten Steckplatzes geändert werden kann.

Das "=" zeigt einen konstanten Steckplatz an, daher gibt es keinen entsprechenden 'Elternteil:'. Das buchstäbliche Objekt, das der Anfangswert des 'Fahrzeugs' ist, enthält einen einzelnen Steckplatz, damit sich Nachrichten im Zusammenhang mit dem Klonen verstehen können. Ein wirklich leeres Objekt, das als (|) oder einfacher als () angezeigt wird, kann überhaupt keine Nachrichten erhalten.

Fahrzeug _Fügt hinzu: (| Name <- 'Automobil'|). 

Hier ist der Empfänger das vorherige Objekt, das jetzt "Name" und "Name" und "Slots zusätzlich zu" Eltern*"enthält.

_Fügt hinzu: (| Sportwagen <- Fahrzeug Kopieren |). Sportwagen _Fügt hinzu: (| zur Arbeit fahren = ('' 'etwas Code, Dies ist a Methode'' ') |). 

Obwohl zuvor "Fahrzeug" und "Sportscar" genau gleich waren, enthält letztere einen neuen Slot mit einer Methode, die das Original nicht hat. Methoden können nur in konstante Slots enthalten sein.

_Fügt hinzu: (| Porsche911 <- Sportwagen Kopieren |). Porsche911 Name:"Bob Porsche". 

Das neue Objekt 'Porsche911' begann genau wie "Sportscar", aber die letzte Nachricht änderte den Wert seines Namens "Name". Beachten Sie, dass beide immer noch genau die gleichen Slots haben, obwohl einer von ihnen einen anderen Wert hat.

Umfeld

Ein Merkmal des Selbst ist, dass es auf derselben Art von basiert virtuelle Maschine System, das frühere SmallTalk -Systeme verwendeten. Das heißt, Programme sind nicht eigenständige Entitäten wie in Sprachen wie sind sie Cbrauchen aber ihre gesamte Speicherumgebung, um zu laufen. Dies erfordert, dass Anwendungen in Stücken des gespeicherten Speichers versendet werden Schnappschüsse oder Bilder. Ein Nachteil dieses Ansatzes ist, dass Bilder manchmal groß und unhandlich sind. Das Debuggen eines Bildes ist jedoch oft einfacher als die Debugie traditioneller Programme, da der Laufzeitzustand einfacher zu inspizieren und zu ändern ist. (Der Unterschied zwischen quellbasierter und bildbasierter Entwicklung ist analog zum Unterschied zwischen klassenbasierter und prototypischer objektorientierter Programmierung.)

Darüber hinaus ist die Umgebung auf die schnelle und kontinuierliche Änderung der Objekte im System zugeschnitten. Das Refactoring eines "Klasse" -Designs ist so einfach wie das Ziehen von Methoden aus den vorhandenen Vorfahren in neue. Einfache Aufgaben wie Testmethoden können erledigt werden, indem eine Kopie erstellt, die Methode in die Kopie gezogen und dann geändert wird. Im Gegensatz zu herkömmlichen Systemen verfügt nur das veränderte Objekt über den neuen Code, und es muss nichts umgebaut werden, um ihn zu testen. Wenn die Methode funktioniert, kann sie einfach wieder in den Vorfahr zurückgezogen werden.

Leistung

Selbst VMs erzielten eine Leistung von ungefähr der Hälfte der Geschwindigkeit von optimiertem C bei einigen Benchmarks.[6]

Dies wurde durch erreicht durch Just-in-Time-Zusammenstellung Techniken, die in der Selbstforschung Pionierarbeit und verbessert wurden, um eine hochrangige Sprache zu machen, können dies gut abschneiden.

Müllsammlung

Das Müllsammler für Selbstgebrauch Generation Müllsammlung die Objekte nach Alter getrennt. Durch die Verwendung des Speicherverwaltungssystems zur Aufzeichnung von Seite schreibt ein Schreibbarrier. Diese Technik bietet eine hervorragende Leistung, obwohl nach einiger Zeit eine vollständige Müllsammlung auftreten kann und eine beträchtliche Zeit in Anspruch nimmt.[vage]

Optimierungen

Das Laufzeitsystem flacht selektiv auf. Dies ergibt bescheidene Beschleunigungen an sich, ermöglicht jedoch eine umfassende Ausschnitten von Typinformationen und mehrere Codeversionen für verschiedene Anrufertypen. Dies beseitigt die Notwendigkeit, viele Methodensuche und ermöglicht bedingte Ast-Anweisungen und hartcodierte Anrufe, die eingefügt werden-häufig eine C-ähnliche Leistung ohne Verlust der Allgemeinheit auf Sprachebene, jedoch auf einem vollständig müllgesammelten System.[7]

Siehe auch

Verweise

  1. ^ Ungar, David; Smith, Randall B. (2007). "Selbst". Verfahren der dritten ACM Sigplan -Konferenz über die Geschichte der Programmiersprachen (HOPL III). doi:10.1145/1238844.1238853. ISBN 9781595937667. S2CID 220937663.
  2. ^ "Selbst" Mandarin "2017.1". 24. Mai 2017. archiviert von das Original am 24. Mai 2017. Abgerufen 24. Mai 2017.
  3. ^ Wolczko, Mario (1996). "Selbst umfasst: SmallTalk". Workshop zu prototypbasierten Sprachen, ECOOP '96, Linz, Österreich.
  4. ^ "Self 4.4 veröffentlicht". 16. Juli 2010. archiviert von das Original am 5. Dezember 2017. Abgerufen 24. Mai 2017.
  5. ^ "Selbstmassed (4.5.0) veröffentlicht". 12. Januar 2014. archiviert von das Original am 6. Dezember 2017. Abgerufen 24. Mai 2017.
  6. ^ AGESEN, OLE (März 1997). "Design und Implementierung von PEP, einem Java-Just-in-Time-Übersetzer". sun.com. Archiviert von das Original am 24. November 2006.
  7. ^ [1][Dead Link]

Weitere Lektüre

Externe Links