Sì, c'è davvero. Una specie di.
Newspeak non ha uno stato statico né uno stato globale. Ciò significa che l'unico modo possibile per ottenere l'accesso a una dipendenza è farla esplicitamente iniettare. Ovviamente, ciò significa che la lingua, o nel caso di Newspeak più precisamente, l'IDE deve rendere facile l'iniezione di dipendenza, altrimenti la lingua sarà inutilizzabile.
Quindi, il linguaggio non è progettato per DI, piuttosto la necessità di DI è una conseguenza del design del linguaggio.
Se non esiste uno stato statico né uno stato globale, non puoi semplicemente "raggiungere" l'etere ed estrarre qualcosa. Ad esempio, in Java, la struttura del pacchetto è statica. Posso solo dire java.lang.String
e ho me stesso la String
lezione. Questo non è possibile in Newspeak. Tutto ciò con cui lavori, ti deve essere esplicitamente fornito, altrimenti non puoi ottenerlo. Quindi, tutto è una dipendenza e ogni dipendenza è esplicita.
Vuoi una stringa? Bene, devi prima chiedere stdlib
all'oggetto di consegnarti la String
classe. Oh, ma come si accede a stdlib
? Bene, devi prima chiedere platform
a di consegnarti l' stdlib
oggetto. Oh, ma come si accede a platform
? Bene, devi prima chiedere a qualcun altro di consegnarti l' platform
oggetto. Oh, ma come si accede a quella persona? Bene, devi prima chiedere a qualcun altro di consegnarti l'oggetto.
Fino a che punto arriva nella tana del coniglio? Dove si ferma la ricorsione? Fino in fondo, in realtà. Non si ferma. Quindi, come puoi scrivere un programma in Newspeak? Beh, a rigor di termini, non puoi!
Hai bisogno di qualche entità esterna che lega tutto insieme. In Newspeak, quell'entità è l'IDE. L'IDE vede l'intero programma. Può collegare insieme i diversi pezzi. Lo schema standard in Newspeak è che la classe centrale della tua applicazione ha un accessor chiamato platform
e l'IDE di Newspeak inietta un oggetto in quell'accessorio che ha metodi che restituiscono alcune delle necessità di base della programmazione: una String
classe, una Number
classe, una Array
classe, e così via.
Se si desidera testare l'applicazione, è possibile iniettare un platform
oggetto il cui File
metodo restituisce una classe con metodi fittizi. Se desideri distribuire la tua applicazione sul cloud, devi iniettare una piattaforma la cui File
classe è effettivamente supportata da Amazon S3. Le GUI multipiattaforma funzionano iniettando diversi framework GUI per diversi sistemi operativi. Newspeak ha persino un compilatore sperimentale da Newspeak a ECMAScript e un framework GUI supportato da HTML che ti consente di trasferire un'applicazione GUI completamente funzionante dal desktop nativo nel browser senza modifiche, semplicemente iniettando diversi elementi GUI.
Se si desidera distribuire l'applicazione, l'IDE può serializzare l'applicazione in un oggetto su disco. (A differenza del suo antenato, Smalltalk, Newspeak ha un formato di serializzazione di oggetti fuori dall'immagine. Non è necessario portare l'intera immagine con sé, proprio perché tutte le dipendenze vengono iniettate: l'IDE conosce esattamente quali parti del sistema vengono utilizzate dall'applicazione usa e non lo fa. Quindi serializza esattamente il sottografo connesso dello spazio oggetti che comprende la tua applicazione, niente di più.)
Tutto questo funziona semplicemente portando l'orientamento agli oggetti all'estremo: tutto è una chiamata di metodo virtuale ("messaggio di invio" nella terminologia di Smalltalk, di cui Newspeak è un discendente). Anche la ricerca di superclasse è una chiamata di metodo virtuale! Prendi qualcosa del genere
class Foo extends Bar // using Java syntax for familiarity
o, in Newspeak:
class Foo = Bar () () : ()
In Java, questo creerà un nome Foo
nello spazio dei nomi globale statico, cercherà Bar
nello spazio dei nomi globale statico e creerà Bar
Foo
la superclasse. Anche in Ruby, che è molto più dinamico, ciò creerà comunque una costante statica nello spazio dei nomi globale.
In Newspeak, la dichiarazione equivalente significa: creare un metodo getter denominato Foo
e renderlo restituire una classe che cerca la sua superclasse chiamando il metodo denominato Bar
. Nota: questo non è come Ruby, in cui è possibile inserire qualsiasi codice Ruby eseguibile come dichiarazione di superclasse, ma il codice verrà eseguito solo una volta quando viene creata la classe e il valore restituito di quel codice diventa la superclasse fissa. No. Il metodo Bar
viene chiamato per ogni singola ricerca del metodo!
Ciò ha alcune profonde implicazioni:
- poiché un mixin è fondamentalmente una classe che non conosce ancora la sua superclasse, e in Newspeak la superclasse è una chiamata di metodo virtuale dinamica, e quindi sconosciuta, ogni classe è automaticamente anche un mixin. Ottieni mixin gratuitamente.
poiché una classe interna è solo una chiamata di metodo che restituisce una classe, è possibile sovrascrivere quel metodo in una sottoclasse della classe esterna, quindi ogni classe è virtuale. Ottieni lezioni virtuali gratuitamente:
class Outer {
class Inner { /* … */ }
}
class Sub extends Outer {
override class Inner { /* … */ }
}
Neolingua:
class Outer = () (
class Inner = () () : ()
) : ()
class Sub = Outer () (
class Inner = () () : ()
) : ()
poiché la superclasse è solo una chiamata di metodo che restituisce una classe, è possibile sovrascrivere quel metodo in una sottoclasse della classe esterna, le classi interne definite nella superclasse possono avere una superclasse diversa nella sottoclasse. Ottieni l'eredità della gerarchia di classi gratuitamente:
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`!!!
}
Neolingua:
class Outer = () (
class MyCoolArray = Array () () : ()
) : ()
class Sub = Outer () (
class Array = () () : ()
) : ()
e, infine, il più importante per questa discussione: poiché (a parte quelli che hai definito nella tua classe, ovviamente) puoi solo chiamare metodi nelle tue classi che si chiudono in modo lessicale e nelle tue superclassi, una classe più esterna di livello superiore non può chiamare qualsiasi metodo a tutti tranne quelli che sono esplicitamente iniettati: una classe di livello superiore non hanno una classe contenitrice cui metodi potrebbe chiamare, e non può avere una superclasse diversa da quella predefinita, poiché la dichiarazione superclasse è un metodo di chiamata, e ovviamente non può andare alla superclasse (lo èla superclasse) e inoltre non può andare alla classe che racchiude il lessico, perché non ce n'è. Ciò significa che le classi di livello superiore sono completamente incapsulate, possono accedere solo a ciò che vengono esplicitamente iniettate e vengono iniettate solo ciò che chiedono esplicitamente. In altre parole: le classi di livello superiore sono moduli. Ottieni un intero sistema di moduli gratuitamente. In effetti, per essere più precisi: le classi di livello superiore sono dichiarazioni di moduli, le sue istanze sono moduli. Quindi, ottieni un sistema di moduli con dichiarazioni di moduli parametrici e moduli di prima classe gratuiti, cosa che molti sistemi di moduli, anche molto sofisticati, non possono fare.
Al fine di rendere indolore questa iniezione, le dichiarazioni di classe hanno una struttura insolita: sono costituite da due dichiarazioni. Uno è il costruttore della classe, che non è il costruttore che costruisce istanze della classe, ma piuttosto il costruttore che costruisce l'ambiente in cui viene eseguito il corpo della classe. In una sintassi simile a Java, sarebbe simile a questo:
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"
}
Neolingua:
class Foo using: platform = Bar (
Array = platform collections Array
String = platform streams String
File = platform files ExternalReadWriteStream
) (
class MyArray = Array () () : ()
) : ()
Nota che il modo in cui un programmatore di Newspeak vedrà effettivamente le classi è così:
Non posso nemmeno iniziare a rendergli giustizia, comunque. Dovrai giocarci da solo. Gilad Bracha ha tenuto un paio di conferenze su vari aspetti del sistema, inclusa la modularità. Ha tenuto un discorso davvero lungo (2 ore) , la cui prima ora è un'introduzione approfondita al linguaggio, inclusa la storia della modularità. Il capitolo 2 della piattaforma di programmazione Newspeak tratta la modularità. Se sfogli Newspeak su Squeak - A Guide for the Perplexed (alias Newspeak-101) , avrai un'idea del sistema. Newspeak per esempio è un documento live (cioè è in esecuzione all'interno della porta Newspeak-on-ECMASCript, ogni riga di codice è modificabile, ogni risultato è ispezionabile) che dimostra la sintassi di base.
Ma davvero, devi giocarci intorno. È così diverso da tutti i linguaggi mainstream e anche dalla maggior parte dei non mainstream che è difficile da spiegare, deve essere sperimentato.