We now re-cast the changes of the previous section as language evolution pressures, discussing: the factors that keep programming languages alive (Sect. 3.1), the forces that lead to language evolution (Sect. 3.2), and cases where languages have become practically extinct due to not having evolved (Sect. 3.3).

3.1 Factors that Keep Programming Languages Alive

Although the landscape of programming languages evolves, many languages take root and stick around. We observe several forces that keep languages alive. In the evolutionary model, these ‘forces’ sum to contribute to the overall fitness of a language in a given niche.

Legacy Software. The amount of software in the world increases day by day. New systems (and modules within systems) are created at a much faster rate than they are deleted. Existing code that performs valuable business functions needs to be updated and upgraded to provide additional functionality or to integrate with other systems. Replacing a system wholesale is a major decision, and costly for large systems. The need to tend to existing successful systems, using whatever language they were originally written in, is a strong force in keeping languages alive. Even though COBOL is often perceived as a dead language, as recently as 2009, it was estimated to have billions of lines of code in active use8 and some of these surely remain, even if they are not widely advertised.

Community. Enthusiasm and support for a particular programming language is often fostered if there is an active and encouraging community around it. This can be helpful in encouraging beginners, or in supporting programmers in their daily tasks, by providing advice on technical problems as they come up. Language communities, like any social group, tend to reflect the design parameters of the language they discuss; some are seen as formal and academic and others more down-to-earth.. For example, there is a saying in the Ruby community, which has a reputation for being supportive and helpful: “Matz [the language creator] is nice and so we are nice”.9 In contrast, the community that has grown up around Scala is perceived to be much more academically focused, biased towards more mathematical thinking and language, and sometimes perceived as less welcoming to people from a “general developer” background. In his (somewhat polemical) ScalaDays 2013 keynote10, Rod Johnson gives his impressions of the Scala community as being somewhere where “there do seem to be quite a few people who aren’t highly focused on solving real world problems” and where some members appear to have the opinion that “ignorance should be punished”.

Ease of Getting Started. In order for a new language to take hold, it helps if it is easy for new programmers (either novices, or just newcomers to the language in question) to get started quickly. The speed with which a new programmer can write and run their first program depends on many things: the simplicity of language design, clarity of tutorials, the amount one needs to learn before getting started, and the support of tooling (including helpful error messages, a subject taken to heart by languages like Elm). This in turn can affect the longevity of a language—as this depends on a continued influx of new programmers.

Habitability. In his book Patterns of Software [12], Gabriel describes the characteristic of habitability: “Habitability makes a place livable, like home. And this is what we want in software—that developers feel at home, can place their hands on any item without having to think deeply about where it is.” If a language has widely adopted idioms, and projects developed in that language are habitually laid out according to familiar structure then it easy for programmers to feel at home. Languages that promote “one way to do things” may help to engender this consistency. Habitability may also come from having a common tool-ecosystem11. For example, if we download a Java project and find that it is structured as a Maven12 project, then it is easy to locate the source, tests, dependencies, build configuration, etc., if we are familiar with other Maven projects. Similarly in modern Ruby projects we might expect a certain structure and the use of Bundler13 to perform a similar role. These sort of tools are often only de-facto standards, as a result of wide adoption, but consistent project layout, build process, etc., provided by standard tools, reduces cognitive load for the developer, and in turn may make a programmer feel more at home working in a given language, especially when coming to work on a new project [14].

Libraries. The availability of libraries of reusable code adds to the ease of getting things done in a particular language. Whether we want to read a file, invoke a web service over HTTP, or even recognise car licence plates in a photograph, if we can easily find a library to do so in a particular language, that language is appealing for getting the job done in the short term. Some languages come with rich standard libraries as part of their distribution. In other cases the proliferation of community-contributed libraries on sites like GitHub leads to a plethora of options. When there are a large number of libraries available, it often becomes part of the culture in the community centred around a particular language to contribute. The plentiful supply of libraries begets the plentiful supply of libraries. We note, however, that recent trends to rely on third-party libraries for even the simplest of routines can lead to problems. For example, the removal of the widely used ‘left-pad’ library from the ‘npm’ JavaScript package manager caused a great deal of chaos.14

Tools. Although language designers may hope or believe that their new language allows programming tasks to be solved in new, perhaps more elegant ways, it is not the language alone that determines the productivity of a programmer at work. A programmer needs to write and change code, navigate existing code bases, debug, compile, build and test, deploy their code, and often integrate existing components and libraries, in order to get their work done and to deliver working features into the hands of their users. A programming language therefore exists within a tool-ecosystem.

Java, for example, is a very popular language that is highly productive for many development teams. This is not only down to the design of the language itself—some might argue that it is in fact in spite of this, as Java is often seen as relatively unsophisticated in terms of language features. It is also—indeed, perhaps largely—due to the supply of good tools and libraries that are available to Java developers. Anecdotally we have heard stories from many commercial developers who have actively chosen to work in Java rather than working with a more sophisticated language, due to the availability of powerful Java-focused tools such as IntelliJ’s IDEA,15 with their rich support for automated refactoring and program transformation, contrasted with the comparative lack of tool support for richer languages. This gap in tool support can even inhibit the uptake of JVM-targeted languages such as Scala, something addressed with the recent IntelliJ IDEA support for Scala and Java 9.

To some degree, tools can compensate for perceived deficiencies in a language, and generally evolve faster than the language itself, because a change to a tool does not have the same impact on existing software as a change to a language specification does.

Support of Change. One might think that agile methods would favour dynamically typed languages, and indeed part of their popularity is the sense that they allow a developer to get something done without having to worry about a lot of the “boiler-plate” associated with stricter and more verbose languages. But there is a counter-pressure for statically typed languages when working on large systems. Agile methods promote embracing change, with code bases evolving through a continuous sequence of updates and refactorings [10]. These activities of transforming a code base are more easily done when supported by tools, and refactoring tools work better when type information is available [40]. However, this is not a one-way street. The increased complexity of Scala’s type system over Java makes it harder to create effective automated refactoring tools. Also the additional sophistication of the compiler means that compared to Java the compilation and build times are relatively long. This can lead to frustration when developers want to make frequent small changes.

A workflow that involves making frequent small changes to a working system requires a harness that developers can rely on to mitigate risk and to allow sustainable progress. A practice commonly used by agile teams is test-driven development (TDD) [3]. It is misleading to say that particular languages explicitly support TDD, but in a language like Java or C# with good tooling, we can get a lot done working in a TDD fashion because the tools can generate a lot of our implementation code for us based on tests and types—although this is really just a mechanisation of mundane manual work, there is no real intelligent synthesis at play.16 In dynamic languages we need tests even more, because we have less assurance about the safety and correctness of our program from the type system. Fortunately, some flavours of test—for example tests using mock objects [25]—may be more convenient to write in dynamic languages as we do not have to introduce abstractions to ‘convince’ the type system that a particular test double17 can be used in a type-compatible manner as a substitute for a real dependency, given the late binding that is characteristic of such languages.

Supply of Talent. When building a new system, the choice of language is not just a technical decision, but also an economic one. Do we have the developers needed to build this system? If we need to hire more, or one day need to replace a current staff member, how much would it cost to hire someone with the relevant skills? Knowledge of some languages is easy to find, whilst others are specialist niches. At the time of writing there is a good supply of programmers in the job market who know Java, C#, JavaScript etc. There are comparatively few Haskell, Rust or Erlang developers. This scarcity of supply relative to demand naturally leads to high prices.

High Performance. Some languages (C and C++ in particular) are not going to die in the immediate future because they are so performant. We return to the longevity of C in Sect. 5.1 and speculate on the future of C and C++ in Sect. 6.1. A design goal of the relatively new Rust language is to achieve C-like performance without sacrificing memory safety, through type system innovations. In order to achieve high performance, Rust in particular aims to provide static guarantees of memory safety, to avoid the overhead of run-time checks.

An Important Niche. Some languages just solve an important class of problem particularly well. Ada is barely used if we look globally, but it is very much alive (particularly the SPARK subset of Ada) for building high-assurance software [28]. The same is true for Fortran, but with respect to scientific computing. Both languages have reasonably recent standards (Ada 2012 and Fortran 2008).