Oui, en effet. Sorte de.
Newspeak n'a ni état statique ni état global. Cela signifie que le seul moyen possible d'accéder à une dépendance est de l'injecter explicitement. Évidemment, cela signifie que le langage, ou dans le cas de Newspeak plus précisément, l'IDE doit faciliter l'injection de dépendances, sinon le langage sera inutilisable.
Ainsi, le langage n'est pas conçu pour DI, mais la nécessité de DI est une conséquence de la conception du langage.
S'il n'y a pas d'état statique ni d'état global, alors vous ne pouvez pas simplement "tendre la main" dans l'éther et retirer quelque chose. Par exemple, en Java, la structure du package est un état statique. Je peux juste dire java.lang.String
et j'ai moi-même la String
classe. Ce n'est pas possible dans Newspeak. Tout ce avec quoi vous travaillez doit vous être explicitement fourni, sinon vous ne pouvez pas y accéder. Donc, tout est une dépendance, et chaque dépendance est explicite.
Tu veux une chaîne? Eh bien, vous devez d'abord demander à l' stdlib
objet de vous remettre la String
classe. Oh, mais comment avez-vous accès à la stdlib
? Eh bien, vous devez d'abord demander platform
à vous remettre l' stdlib
objet. Oh, mais comment avez-vous accès à la platform
? Eh bien, vous devez d'abord demander à quelqu'un d'autre de vous remettre l' platform
objet. Oh, mais comment avez-vous accès à cette personne? Eh bien, vous devez d'abord demander à quelqu'un d'autre de vous remettre l'objet.
Jusqu'où descend le terrier du lapin? Où s'arrête la récursivité? Tout le chemin, en fait. Ça ne s'arrête pas. Alors, comment pouvez-vous écrire un programme dans Newspeak? Eh bien, à strictement parler, vous ne pouvez pas!
Vous avez besoin d'une entité extérieure qui relie tout cela. Dans Newspeak, cette entité est l'IDE. L'IDE voit tout le programme. Il peut câbler les pièces disparates ensemble. Le modèle standard dans Newspeak est que la classe centrale de votre application a un accesseur appelé platform
, et l'IDE Newspeak injecte un objet dans cet accesseur qui a des méthodes qui renvoient certaines des nécessités de base de la programmation: une String
classe, une Number
classe, une Array
classe, etc.
Si vous souhaitez tester votre application, vous pouvez injecter un platform
objet dont la File
méthode renvoie une classe avec des méthodes factices. Si vous souhaitez déployer votre application dans le cloud, vous injectez une plate-forme dont la File
classe est réellement soutenue par Amazon S3. Les interfaces graphiques multiplateformes fonctionnent en injectant différents cadres d'interface graphique pour différents systèmes d'exploitation. Newspeak a même un compilateur expérimental Newspeak-to-ECMAScript et une infrastructure graphique basée sur HTML qui vous permet de porter une application GUI complète depuis le bureau natif dans le navigateur sans aucun changement, juste en injectant différents éléments GUI.
Si vous souhaitez déployer votre application, l'EDI peut sérialiser l'application en un objet sur disque. (Contrairement à son ancêtre, Smalltalk, Newspeak a un format de sérialisation d'objet hors image. Vous n'avez pas besoin de prendre la totalité de l'image avec vous, précisément parce que toutes les dépendances sont injectées: l'EDI sait exactement quelles parties du système votre application utilise et ce qu'il ne fait pas. Donc, il sérialise exactement le sous-graphe connecté de l'espace objet qui comprend votre application, rien de plus.)
Tout cela fonctionne simplement en poussant à l'extrême l'orientation objet: tout est un appel de méthode virtuel ("message send" dans la terminologie Smalltalk, dont Newspeak est un descendant). Même la recherche de superclasse est un appel de méthode virtuelle! Prenez quelque chose comme
class Foo extends Bar // using Java syntax for familiarity
ou, dans Newspeak:
class Foo = Bar () () : ()
En Java, cela va créer un nom Foo
dans l'espace de noms global statique, rechercher Bar
dans l'espace de noms global statique et créer Bar
Foo
la superclasse. Même dans Ruby, qui est beaucoup plus dynamique, cela créera toujours une constante statique dans l'espace de noms global.
Dans Newspeak, la déclaration équivalente signifie: créer une méthode getter nommée Foo
et lui faire retourner une classe qui recherche sa superclasse en appelant la méthode nommée Bar
. Remarque: ce n'est pas comme Ruby, où vous pouvez mettre n'importe quel code Ruby exécutable comme déclaration de superclasse, mais le code ne sera exécuté qu'une seule fois lorsque la classe sera créée et la valeur de retour de ce code deviendra la superclasse fixe. Non. La méthode Bar
est appelée pour chaque recherche de méthode!
Cela a de profondes implications:
- puisqu'un mixin est fondamentalement une classe qui ne connaît pas encore sa superclasse, et dans Newspeak, la superclasse est un appel de méthode virtuelle dynamique, et donc inconnue, chaque classe est automatiquement aussi un mixin. Vous obtenez des mixins gratuitement.
puisqu'une classe interne est juste un appel de méthode qui renvoie une classe, vous pouvez remplacer cette méthode dans une sous-classe de la classe externe, donc chaque classe est virtuelle. Vous obtenez des cours virtuels gratuitement:
class Outer {
class Inner { /* … */ }
}
class Sub extends Outer {
override class Inner { /* … */ }
}
Newspeak:
class Outer = () (
class Inner = () () : ()
) : ()
class Sub = Outer () (
class Inner = () () : ()
) : ()
puisque la superclasse est juste un appel de méthode qui renvoie une classe, vous pouvez remplacer cette méthode dans une sous-classe de la classe externe, les classes internes définies dans la superclasse peuvent avoir une superclasse différente dans la sous-classe. Vous obtenez gratuitement l'héritage de la hiérarchie des classes:
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 = () () : ()
) : ()
et enfin, le plus important pour cette discussion: puisque (en dehors de celles que vous avez définies dans votre classe, évidemment), vous ne pouvez appeler que des méthodes dans vos classes lexiquement englobantes et vos superclasses, une classe la plus externe de niveau supérieur ne peut pas appeler de méthodes du tout, sauf celles qui sont explicitement injectées: une classe de niveau supérieur n'a pas de classe englobante dont elle pourrait appeler les méthodes, et elle ne peut pas avoir une superclasse autre que la classe par défaut, car la déclaration de superclasse est un appel de méthode, et il ne peut évidemment pas aller à la superclasse (il estla superclasse) et il ne peut pas non plus aller à la classe lexicalement car il n'y en a pas. Cela signifie que les classes de niveau supérieur sont complètement encapsulées, elles ne peuvent accéder qu'à ce qu'elles sont explicitement injectées et elles ne reçoivent que ce qu'elles demandent explicitement. En d'autres termes: les classes de niveau supérieur sont des modules. Vous obtenez gratuitement un système complet de modules. En fait, pour être plus précis: les classes de niveau supérieur sont des déclarations de module, ses instances sont des modules. Ainsi, vous obtenez gratuitement un système de modules avec des déclarations de modules paramétriques et des modules de première classe, ce que de nombreux systèmes de modules, même très sophistiqués, ne peuvent pas faire.
Afin de rendre toute cette injection indolore, les déclarations de classe ont une structure inhabituelle: elles consistent en deux déclarations. L'un est le constructeur de classe, qui n'est pas le constructeur qui construit des instances de la classe, mais plutôt le constructeur qui construit l'environnement dans lequel le corps de classe s'exécute. Dans une syntaxe de type Java, cela ressemblerait à ceci:
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 () () : ()
) : ()
Notez que la façon dont un programmeur Newspeak va réellement voir les classes est comme ceci:
Mais je ne peux même pas commencer à lui rendre justice. Vous devrez jouer avec vous-même. Gilad Bracha a donné quelques conférences sur divers aspects du système, y compris la modularité. Il a donné un très long exposé (2 heures) , dont la première heure est une introduction approfondie à la langue, y compris l'histoire de la modularité. Le chapitre 2 de la plateforme de programmation Newspeak traite de la modularité. Si vous parcourez Newspeak sur Squeak - A Guide for the Perplexed (aka Newspeak-101) , vous aurez une idée du système. Newspeak by Example est un document en direct (c'est-à-dire qu'il s'exécute à l'intérieur du port Newspeak-on-ECMASCript, chaque ligne de code est modifiable, chaque résultat est inspectable) démontrant la syntaxe de base.
Mais vraiment, vous devez jouer avec. Il est tellement différent de toutes les langues traditionnelles et même de la plupart des langues non traditionnelles qu'il est difficile à expliquer, il doit être expérimenté.