22

Many general programming languages are flexible enough to allow you to support dependency injection. Even without library or framework support. But even if a language is Turing complete enough to solve any programming problem, a language makes choices that impact what is easy and what is hard to do in them.

Is there any language that was specifically designed to make dependency injection easy, and conversely, make creating hidden dependencies hard?

Clarification:

Due to limitations of some languages (looking at you Java) many people regard assistance with wiring and construction as part of dependency injection. Here I only intend a language designed for DI to mean that dependency's are not easily hidden in side effects. Having a convention over configuration system as well would only be added gravy.

I'm not looking for a language recommendation. It's a historical question. Has any language author ever explicitly set out to do this?

J. Mini
  • 997
  • 8
  • 20
candied_orange
  • 102,279
  • 24
  • 197
  • 315
  • 1
    Strongly related, if not outright duplicate: [How could dependency injection be integrated into the language?](http://programmers.stackexchange.com/q/63557/1204) – Robert Harvey May 25 '16 at 23:13
  • Whee! 3K! Now I can watch them vote to close this question. :) Thanks for the votes. – candied_orange May 25 '16 at 23:15
  • @RobertHarvey I would argue that I'm asking "Does it exist" not "How to do it". – candied_orange May 25 '16 at 23:15
  • 1
    You should read that post anyway. "Does it exist" is a far less interesting question, unless you expand it to something like "how did they do it?" – Robert Harvey May 25 '16 at 23:16
  • @RobertHarvey point taken. I'll wait to mouth off after I've given it a good read. :) – candied_orange May 25 '16 at 23:17
  • You can take Java, remove static variables, and you're 90% of the way there. (The other 10% being global things that aren't variables, like socket addresses) – user253751 May 26 '16 at 08:08
  • 1
    Would Haskell count? With currying and higher-order functions you can solve most problems that DI generally solves in OOP languages and with its strictness on purity you are forced to separate sideeffects like IO etc and functions cannot magically conjure up something that they havent been passed as an argument. You dont get any convention over configuration, but on the other hand I am slowly moving away from that even in my OOP code nowadays since I have noticed that most teams cannot be trusted with that on medium-sized projects and larger. – wasatz May 26 '16 at 13:04
  • The more interesting question is - is there a language or architecture where you do not need DI any more, because there are simply no dependencies between components. (The answer is yes, here is a link to an article about such an architecture: http://www.ieee-student-conference.de/fileadmin/papers/2012/ieeegsc2012_submission_2.pdf). – Doc Brown May 26 '16 at 18:11
  • 1
    @wasatz: Yes, Haskell counts. Most "software patterns" are really just workarounds for shortcomings in the programming language. – Robert Harvey Jun 01 '16 at 23:15
  • @DocBrown I think link rot got your paper. Any idea where to find it today? – candied_orange Oct 21 '22 at 18:12
  • @candied_orange: Try https://web.archive.org/web/20160305002705/http://www.ieee-student-conference.de/fileadmin/papers/2012/ieeegsc2012_submission_2.pdf – Doc Brown Oct 21 '22 at 18:16

4 Answers4

22

Yes, there is indeed. Sort of.

Newspeak has no static state and no global state. This means that the only possible way to get access to a dependency is to have it explicitly injected. Obviously, this means that the language, or in the case of Newspeak more precisely the IDE needs to make dependency injection easy, otherwise the language will be unusable.

So, the language is not designed for DI, rather the necessity for DI is a consequence of the language design.

If there is no static state and no global state, then you cannot just "reach out" in to the ether and pull something out. For example, in Java, the package structure is static state. I can just say java.lang.String and I have myself the String class. That is not possible in Newspeak. Everything you work with, has to be explicitly provided to you, otherwise you just can't get at it. So, everything is a dependency, and every dependency is explicit.

You want a string? Well, you have to first ask the stdlib object to hand you the String class. Oh, but how do you get access to the stdlib? Well, you have to first ask the platform to hand you the stdlib object. Oh, but how do you get access to the platform? Well, you have to first ask someone else to hand you the platform object. Oh, but how do you get access to that someone lese? Well, you have to first ask yet another someone else to hand you the object.

How far down the rabbit hole does this go? Where does the recursion stop? All the way, actually. It doesn't stop. Then, how can you write a program in Newspeak? Well, strictly speaking, you can't!

You need some outside entity that ties it all together. In Newspeak, that entity is the IDE. The IDE sees the whole program. It can wire the disparate pieces together. The standard pattern in Newspeak is that the central class of your application has an accessor called platform, and the Newspeak IDE injects an object into that accessor that has methods which return some of the basic necessities of programming: a String class, a Number class, an Array class, and so on.

If you want to test your application, you can inject a platform object whose File method returns a class with dummy methods. If you want to deploy your application to the cloud, you inject a platform whose File class actually is backed by Amazon S3. Cross-platform GUIs work by injecting different GUI frameworks for different OSs. Newspeak even has an experimental Newspeak-to-ECMAScript compiler and HTML-backed GUI framework that allows you to port a fully-featured GUI application from native desktop into the browser with no changes, just by injecting different GUI elements.

If you want to deploy your application, the IDE can serialize the application into an on-disk object. (Unlike its ancestor, Smalltalk, Newspeak has an out-of-image object serialization format. You don't have to take the entire image with you, precisely because all dependencies are injected: the IDE knows exactly which parts of the system your application uses and which it doesn't. So, it serializes exactly the connected subgraph of the object space that comprises your application, nothing more.)

All of this works simply by taking object-orientation to the extreme: everything is a virtual method call ("message send" in Smalltalk terminology, of which Newspeak is a descendant). Even the superclass lookup is a virtual method call! Take something like

class Foo extends Bar // using Java syntax for familiarity

or, in Newspeak:

class Foo = Bar () () : ()

In Java, this will create a name Foo in the static global namespace, and look up Bar in the static global namespace and make Bar Foo's superclass. Even in Ruby, which is much more dynamic, this will still create a static constant in the global namespace.

In Newspeak, the equivalent declaration means: create a getter method named Foo and make it return a class that looks up its superclass by calling the method named Bar. Note: this is not like Ruby, where you can put any executable Ruby code as the superclass declaration, but the code will only be executed once when the class is created and the return value of that code becomes the fixed superclass. No. The method Bar is called for every single method lookup!

This has some profound implications:

  • since a mixin is basically a class that doesn't know its superclass yet, and in Newspeak, the superclass is a dynamic virtual method call, and thus unknown, every class is automatically also a mixin. You get mixins for free.
  • since an inner class is just a method call that returns a class, you can override that method in a subclass of the outer class, so every class is virtual. You get virtual classes for free:

    class Outer {
      class Inner { /* … */ }
    }
    
    class Sub extends Outer {
      override class Inner { /* … */ }
    }
    

    Newspeak:

    class Outer = () (
      class Inner = () () : ()
    ) : ()
    
    class Sub = Outer () (
      class Inner = () () : ()
    ) : ()
    
  • since the superclass is just a method call that returns a class, you can override that method in a subclass of the outer class, inner classes defined in the superclass can have a different superclass in the subclass. You get class hierarchy inheritance for free:

    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 = () () : ()
    ) : ()
    
  • and lastly, the most important for this discussion: since (apart from the ones you defined in your class, obviously) you can only call methods in your lexically enclosing class(es) and your superclass(es), a top-level outermost class cannot call any methods at all except the ones that are explicitly injected: a top-level class doesn't have an enclosing class whose methods it could call, and it cannot have a superclass other than the default one, because the superclass declaration is a method call, and it obviously can't go to the superclass (it is the superclass) and it also can't go to the lexically enclosing class, because there isn't any. What this means is the top-level classes are completely encapsulated, they can only access what they explicitly get injected, and they only get injected what they explicitly ask for. In other words: top-level classes are modules. You get an entire module system for free. In fact, to be more precise: top-level classes are module declarations, its instances are modules. So, you get a module system with parametric module declarations and first-class modules for free, something which many, even very sophisticated, module systems cannot do.

In order to make all of this injection painless, class declarations have an unusual structure: they consist of two declarations. One is the class constructor, which is not the constructor which constructs instances of the class, but rather the constructor that constructs the environment in which the class body runs. In a Java-like syntax, it would look something like this:

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 () () : ()
) : ()

Note that the way a Newspeak programmer is actually going to see the class(es) is like this:Newspeak IDE displaying multiple nested classes

I can't even begin to do it justice, though. You'll have to play around with it yourself. Gilad Bracha has given a couple of talks about various aspects of the system, including modularity. He gave a really long (2hr) talk, the first hour of which is a thorough introduction to the language, including the modularity story. Chapter 2 of The Newspeak Programming Platform covers modularity. If you skim Newspeak on Squeak – A Guide for the Perplexed (aka Newspeak-101), you get a feel for the system. Newspeak by Example is a live document (i.e. it is running inside the Newspeak-on-ECMASCript port, every line of code is editable, every result is inspectable) demonstrating the basic syntax.

But really, you have to play around with it. It is just so different from all mainstream and even most non-mainstream languages that it is hard to explain, it has to be experienced.

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
  • 3
    Meh. Forbid the use of static state and global state, and you could say this about almost any modern programming language. – Robert Harvey May 25 '16 at 23:15
  • Curious, many of my hand made injection containers are static factories. Hadn't thought of that as a bad thing before. – candied_orange May 25 '16 at 23:30
  • @Jörg Any way you could back up this answer a little more? I've googled "newspeaklanguage.org dependency injection" and came up empty. Closest thing I could find was this: https://news.ycombinator.com/item?id=9620561 – candied_orange May 26 '16 at 00:29
  • @CandiedOrange: I was in the process of expanding the answer but then "real world" interfered. Is that better? – Jörg W Mittag May 26 '16 at 01:50
  • 3
    @JörgWMittag Holy crap! Well it's certainly "more". Hang on while I evaluate "better". Might need the power of a bathroom visit to get through this. – candied_orange May 26 '16 at 02:09
  • Um wow. That's very cool. But why are all your examples in pseudo code? How horrible is the real code syntax? – candied_orange May 26 '16 at 04:47
  • @CandiedOrange: 1) We are talking about semantics here, syntax is mostly irrelevant, 2) I guess there are more people here that can at least *somewhat* decipher C++/C♯/Java/ECMAScript/D/Scala-style code than Newspeak (which is inspired by but still very distinct from Smalltalk and Self), I didn't want to have to include a Newspeak syntax tutorial, 3) which syntax? The current syntax version is NS3, but there is still a lot of NS2 code in the system, and neither of those is the final syntax (and it is not yet decided what the final syntax will be). 4) when working with the system, you will … – Jörg W Mittag May 26 '16 at 11:38
  • … actually mostly be creating methods and classes by clicking on "create method" or "create class" in the IDE, so you will mostly not even see the syntax for classes or methods. Nevertheless, I'll see if I can add equivalent NS3 code to the examples. – Jörg W Mittag May 26 '16 at 11:41
  • 1) True. 2) The children of C do seem to be the dominate syntax. 3) The syntax I did find on the web for newspeak not horrible. 4) I've worked in GUI based programming languages before (filemaker). One of the biggest drawbacks is you can't use your text tools. No renaming by search and replace. No refactoring by finding every call and adding a parameter. Does newspeak have it's own developed IDE tools to make up for that or is that relegated to future development? – candied_orange May 26 '16 at 16:58
  • BTW I found a [video](https://channel9.msdn.com/shows/Going+Deep/Gilad-Bracha-Inside-Newspeak/) that talks about dependency in newspeak at 3:55 – candied_orange May 26 '16 at 16:58
  • @CandiedOrange: Finally got around to adding the equivalent Newspeak source. – Jörg W Mittag Jun 16 '16 at 13:44
  • @CandiedOrange: Refactorings like this have been supported in Smalltalk IDEs for a long time. After all, Refactoring was invented in Smalltalk and the first Automated Refactoring Browser was implemented in and for Smalltalk IDEs, when Java didn't even really have IDEs yet. (Nice bit of history: when IBM noticed the similarities between Smalltalk and Java, they added Java support to their existing Smalltalk system, the result was the Universal Virtual Machine which could execute both Smalltalk and JVM bytecodes, an implementation of the JRE that was actually written in Smalltalk(!) and the … – Jörg W Mittag Jun 16 '16 at 15:51
  • … VisualAge for Java IDE, which was just a slightly modified version of VisualAge for Smalltalk, and also written in Smalltalk. Then, they re-wrote VisualAge for Java in Java, calling it VisualAge for Java Micro Edition, and then they split that up into independent components and released it as open source under the name of … Eclipse (tada!). Yes, one of the most widely-used Java IDEs is actually a Smalltalk IDE, and many of the cool features you are used to were inherited that way.) However, [Newspeak isn't there yet](https://groups.google.com/forum/#!topic/newspeaklanguage/My7PDP4IDeA). – Jörg W Mittag Jun 16 '16 at 15:54
  • @CandiedOrange [I found a really long (2hr) talk](http://meetup.com/Lambda-Meetup-Group/events/223708362/), the first hour of which is a thorough introduction to the language, including the modularity story. After that, he starts to let the audience drive the talk, and thus it starts to wander a bit. Unfortunately, he was invited on short notice and thus didn't have to time to prepare a demo, and is running a bleeding edge VM, so some of the stuff that is interesting about how the IDE ties into the modularity story breaks all over the place :-D – Jörg W Mittag Jun 18 '16 at 10:31
7

The Wake Programming language is designed to use dependency injection. Basically, it has the equivalent of a dependency injection framework baked into the language itself. Classes define the parameters they need and provide and the compiler hooks everything up.

Winston Ewert
  • 24,732
  • 12
  • 72
  • 103
6

It's not a practically useful language, but the system described in this paper.has an interesting effect: it allows you to write an abstract class using abstract classes/interfaces (including instantiating them) Your class can then be made concrete by substituting a subclasses of each abstract class you've used at the point of instantiation. Doing so removes the need for dependency injection in at least simple cases, for example (using a hypothetical version of Java extended with this feature) we could take this code:

public interface I {
    void something ();
)

public class Concrete implements I {
    public void something () { ... }
}

public class Client {
    I myI;
    public Client (I injected) { myI = injected; }
    ...
}

...

    Client c = new Client (new Concrete());
    ...

and replace Client and its usage with:

public class Client {
   I myI = new I();
   ...
}

   Client c = new Client { I -> Concrete } ();

Note that this simplifies the point of use of a dependency, rather than creation. It also allows us to avoid the Factory pattern (as a new I can be created on demand whenever we want).

Jules
  • 17,614
  • 2
  • 33
  • 63
  • Interesting. This reminds me of Scala's Type Members, which can also be overridden in subclasses, and left abstract in a superclass. Abstract Type Members combined with Self-Type Annotations form the basis of Scala's approach to modularity and dependency injection. I'm not at all surprised that this paper has been cited by both [Martin Odersky](http://link.springer.com/chapter/10.1007%2F978-1-4471-3794-8_10), the designer of Scala, and [Gilad Bracha](http://dl.acm.org/citation.cfm?id=165893&CFID=790791416&CFTOKEN=78910743), the designer of Newspeak. – Jörg W Mittag May 26 '16 at 11:32
0

I haven't used it, but the Plastic programming language's official tagline is "What happens if you take dependency injection and bake it into a programming language?". It seems pretty interesting

B1CL0PS
  • 109
  • 1