Ja, das gibt es tatsächlich. Art von.
Newspeak hat keinen statischen und keinen globalen Zustand. Dies bedeutet, dass die einzige Möglichkeit, auf eine Abhängigkeit zuzugreifen, darin besteht, sie explizit einzufügen. Offensichtlich bedeutet dies , dass die Sprache, oder im Fall von Neusprech genauer gesagt die IDE Bedürfnisse zu Dependency Injection leicht zu machen, da sonst die Sprache wird unbrauchbar.
Die Sprache ist also nicht für DI ausgelegt, sondern die Notwendigkeit für DI ist eine Konsequenz des Sprachentwurfs.
Wenn es keinen statischen und keinen globalen Zustand gibt, kann man nicht einfach in den Äther "hineingreifen" und etwas herausziehen. In Java ist die Paketstruktur beispielsweise ein statischer Zustand. Ich kann nur sagen java.lang.String
und ich habe selbst die String
Klasse. Das ist in Newspeak nicht möglich. Alles, mit dem Sie arbeiten, muss Ihnen explizit zur Verfügung gestellt werden, sonst können Sie es einfach nicht erreichen. Also, alles ist eine Abhängigkeit, und jede Abhängigkeit ist explizit.
Du willst einen String? Nun, Sie müssen zuerst das stdlib
Objekt bitten , Ihnen die String
Klasse zu übergeben. Oh, aber wie kommst du zum stdlib
? Naja, du musst den erst bitten platform
, dir das stdlib
Objekt zu übergeben. Oh, aber wie kommst du zum platform
? Nun, Sie müssen zuerst jemanden bitten, Ihnen das platform
Objekt zu übergeben. Oh, aber wie kommst du zu dieser Person? Nun, Sie müssen erst noch jemanden bitten, Ihnen das Objekt zu übergeben.
Wie weit geht das im Kaninchenbau? Wo hört die Rekursion auf? Eigentlich den ganzen Weg. Es hört nicht auf. Wie können Sie dann ein Programm in Newspeak schreiben? Genau genommen kann man das nicht!
Sie brauchen eine externe Instanz, die alles zusammenhält. In Newspeak ist diese Entität die IDE. Die IDE sieht das gesamte Programm. Es kann die unterschiedlichen Stücke zusammen verdrahten. Das Standardmuster in Newspeak ist, dass die zentrale Klasse Ihrer Anwendung einen Accessor namens platform
hat und die Newspeak-IDE ein Objekt in diesen Accessor einfügt, das über Methoden verfügt, die einige der grundlegenden Programmieranforderungen zurückgeben: eine String
Klasse, eine Number
Klasse, eine Array
Klasse, und so weiter.
Wenn Sie Ihre Anwendung testen möchten, können Sie ein platform
Objekt einfügen, dessen File
Methode eine Klasse mit Dummy-Methoden zurückgibt. Wenn Sie Ihre Anwendung in der Cloud bereitstellen möchten, fügen Sie eine Plattform ein, deren File
Klasse tatsächlich von Amazon S3 unterstützt wird. Plattformübergreifende GUIs funktionieren durch Injizieren verschiedener GUI-Frameworks für verschiedene Betriebssysteme. Newspeak verfügt sogar über einen experimentellen Newspeak-to-ECMAScript-Compiler und ein HTML-unterstütztes GUI-Framework, mit dem Sie eine voll funktionsfähige GUI-Anwendung vom nativen Desktop in den Browser portieren können, indem Sie einfach verschiedene GUI-Elemente einfügen.
Wenn Sie Ihre Anwendung bereitstellen möchten, kann die IDE die Anwendung in ein Objekt auf der Festplatte serialisieren. (Im Gegensatz zu seinem Vorgänger Smalltalk verfügt Newspeak über ein Out-of-Image-Objekt-Serialisierungsformat. Sie müssen nicht das gesamte Image mitnehmen, da alle Abhängigkeiten injiziert werden: Die IDE weiß genau, welche Teile des Systems Ihre Anwendung enthält verwendet und was nicht. Also serialisiert es genau den verbundenen Untergraphen des Objektraums, der Ihre Anwendung umfasst, nicht mehr.)
All dies funktioniert einfach, indem die Objektorientierung auf das Äußerste gehoben wird: Alles ist ein virtueller Methodenaufruf ("message send" in der Smalltalk-Terminologie, von der Newspeak abstammt). Sogar die Superklasse-Suche ist ein virtueller Methodenaufruf! Nimm so etwas wie
class Foo extends Bar // using Java syntax for familiarity
oder in Newspeak:
class Foo = Bar () () : ()
In Java wird dadurch ein Name Foo
im statischen globalen Namespace erstellt und Bar
im statischen globalen Namespace nachgeschlagen und die Bar
Foo
Superklasse von make erstellt . Selbst in Ruby, das viel dynamischer ist, wird dadurch eine statische Konstante im globalen Namespace erstellt.
In Newspeak bedeutet die entsprechende Deklaration: Erstellen Sie eine Getter-Methode mit dem Namen Foo
und geben Sie eine Klasse zurück, deren Oberklasse durch Aufrufen der benannten Methode ermittelt wird Bar
. Hinweis: Dies ist nicht wie bei Ruby, wo Sie jeden ausführbaren Ruby-Code als Superklasse-Deklaration ablegen können. Der Code wird jedoch nur einmal ausgeführt , wenn die Klasse erstellt wird und der Rückgabewert dieses Codes zur festen Superklasse wird. Nein. Die Methode Bar
wird für jede einzelne Methodensuche aufgerufen !
Dies hat einige tiefgreifende Auswirkungen:
- Da ein Mixin im Grunde genommen eine Klasse ist, die ihre Oberklasse noch nicht kennt, und in Newspeak die Oberklasse ein dynamischer virtueller Methodenaufruf ist und daher unbekannt, ist jede Klasse automatisch auch ein Mixin. Sie erhalten Mixins kostenlos.
Da eine innere Klasse nur ein Methodenaufruf ist, der eine Klasse zurückgibt, können Sie diese Methode in einer Unterklasse der äußeren Klasse überschreiben, sodass jede Klasse virtuell ist. Sie erhalten kostenlos virtuellen Unterricht:
class Outer {
class Inner { /* … */ }
}
class Sub extends Outer {
override class Inner { /* … */ }
}
Newspeak:
class Outer = () (
class Inner = () () : ()
) : ()
class Sub = Outer () (
class Inner = () () : ()
) : ()
Da es sich bei der Superklasse nur um einen Methodenaufruf handelt, der eine Klasse zurückgibt, können Sie diese Methode in einer Unterklasse der äußeren Klasse überschreiben. In der Superklasse definierte innere Klassen können eine andere Superklasse in der Unterklasse haben. Sie erhalten die Klassenhierarchie-Vererbung kostenlos:
class Outer {
class MyCoolArray extends Array { /* … */ }
}
class Sub extends Outer {
override class Array { /* … */ }
// Now, for instances of `Sub`, `MyCoolArray` has a different superclass
// than for instances of `Outer`!!!
}
Newspeak:
class Outer = () (
class MyCoolArray = Array () () : ()
) : ()
class Sub = Outer () (
class Array = () () : ()
) : ()
Und schließlich das Wichtigste für diese Diskussion: Da Sie (abgesehen von den in Ihrer Klasse definierten) nur Methoden in Ihrer lexikalisch einschließenden Klasse (n) und Ihrer Superklasse (n), einer äußersten Klasse der obersten Ebene, aufrufen können nicht aufrufen können alle Methoden an allen außer denen , die explizit injiziert werden: ist ein Top-Level - Klasse nicht eine umschließende Klasse , deren Methoden haben es nennen könnte, und es kann nicht eine übergeordnete Klasse andere als die Standard haben, weil die übergeordnete Klasse Erklärung a Methodenaufruf, und es kann offensichtlich nicht an die Oberklasse gehen (es istdie Oberklasse) und es kann auch nicht in die lexikalisch einschließende Klasse gehen, weil es keine gibt. Dies bedeutet, dass die Klassen der obersten Ebene vollständig gekapselt sind, dass sie nur auf das zugreifen können, was sie explizit injiziert bekommen, und dass sie nur injiziert bekommen, was sie explizit verlangen. Mit anderen Worten: Klassen der obersten Ebene sind Module. Sie erhalten ein komplettes Modulsystem kostenlos. Genauer gesagt: Klassen der obersten Ebene sind Moduldeklarationen, ihre Instanzen sind Module. So erhalten Sie kostenlos ein Modulsystem mit parametrischen Moduldeklarationen und erstklassigen Modulen, was viele, auch sehr anspruchsvolle Modulsysteme nicht können.
Um all diese Injektionen schmerzlos zu machen, haben Klassendeklarationen eine ungewöhnliche Struktur: Sie bestehen aus zwei Deklarationen. Eine davon ist die Klasse Konstruktor, das ist nicht der Konstruktor , das konstruiert Instanzen der Klasse, sondern der Konstruktor, der die Umgebung , in dem Körper läuft die Klasse konstruiert. In einer Java-ähnlichen Syntax würde dies ungefähr so aussehen:
class Foo(platform) extends Bar {
Array = platform.collections.Array
String = platform.lang.String
File = platform.io.File
| // separator between class constructor and class body
class MyArray extends Array { /* … */ }
// Array refers to the method defined above which in turn gets it from the
// platform object that was passed into the class "somehow"
}
Newspeak:
class Foo using: platform = Bar (
Array = platform collections Array
String = platform streams String
File = platform files ExternalReadWriteStream
) (
class MyArray = Array () () : ()
) : ()
Beachten Sie, dass die Art und Weise ein Neusprech Programmierer tatsächlich gehen , um die Klasse (n) zu sehen , ist wie folgt:
Ich kann es aber noch nicht einmal richtig machen. Sie müssen selbst damit herumspielen. Gilad Bracha hat einige Vorträge zu verschiedenen Aspekten des Systems gehalten, einschließlich der Modularität. Er hielt einen wirklich langen (2-stündigen) Vortrag , in dessen erster Stunde eine gründliche Einführung in die Sprache einschließlich der Modularitätsgeschichte gegeben wurde. Kapitel 2 der Newspeak Programming Platform befasst sich mit der Modularität. Wenn Sie Newspeak on Squeak - Ein Leitfaden für Verblüffte (auch bekannt als Newspeak-101) überfliegen , bekommen Sie ein Gefühl für das System. Newspeak by Example ist ein Live-Dokument (dh es wird im Newspeak-on-ECMASCript-Port ausgeführt, jede Codezeile kann bearbeitet werden, jedes Ergebnis kann überprüft werden), das die grundlegende Syntax demonstriert.
Aber man muss wirklich damit herumspielen. Es unterscheidet sich so sehr von allen Mainstream- und sogar den meisten Nicht-Mainstream-Sprachen, dass es schwer zu erklären ist, es muss erlebt werden.