Fengyun Liu

The Death of Programming Languages

Everything that has a birth will end in death. Programming languages are no exceptions.

In this post, I argue that one major factor that accelerates the death of a programming language is the degradation of the qualities of programs written in the language, such as reliability, performance, maintainability, and security. The degradation happens when bad code patterns become mainstream in the community via frameworks, libraries, tutorials, etc.

The Death of Programming Languages

How can a programming language die? Well, literally a language dies when no new programs are written in the language. As new programs must be written to keep the world running, it means users are moving to other languages. Such a move can happen for many reasons:

  • Learning curve
  • Quality of programs: reliability, performance, maintainability, security.
  • Ecosystem: availability of libraries.
  • Tooling: compiler, IDE, debugger, profiler, etc.
  • Productivity: succinct syntax, expressive language feature, tools, libraries, tutorials, community/support.

It is clear that not all the factors above are determined by the inner qualities of the language itself. For example, better tooling depends on investment which in turn depends on the business success of the language, and the latter is a complex technological, social, and economic process.

While the rise and fall of a programming language is a complex phenomenon, the degradation of qualities of programs in a language will accelerate its death. This becomes clear when we examine the success of new programming languages:

  • Java over C/C++: portability, productivity, reliability
  • Scala over Java: productivity, reliability
  • Ruby over Java: productivity
  • Rust over C/C++: reliability
  • Go over Java: performance
  • TypeScript over JavaScript: reliability

Note that when users move to a new language, the dominating reasons are mainly about quality of programs written in the language. Tooling and ecosystem are seldomly mentioned as the major reason for switching to a new language, though they will be certinaly important for the survival of a language.

Early adoption of a new language usually happens in scenarios where the concern for quality of programs outweight the concern for tooling and ecosystem. If the latter is vital for the adoption of a new language, there can hardly be any successful new languages.

Looking from another perspective, if the quality of programs written in a language is degrading, then there will be more incentives for users to move to another language, thus accelerating the death of the language.

Dimensions of Quality

The quality of programs has many dimensions, such as reliability, maintainability, performance, etc. Historically, the language war happens between reliability and performance: Experienced engineers keep writing in assembly code for better performance sacrificing maintainability and portability. It took almost two decades for the wide adoption of high-level languages. Some explanation say that the world has to wait until the old generation of engieers retire. Advances in hardware should also have helped in settling the dispute.

No one can deny the importance of performance. However, programmers need to make informed decisions when facing the tradeoff between performance and reliability. In a lot of cases, a slight difference in performance does not matter much to the end user, but reliability is vital. Meanwhile, architectural and algorithmic improvements should be preferred first before considering inefficiency in the runtime/language.

Productivity Vs. Quality

In the domain of web applications, the concern for productivity sometimes is bigger than the concern for quality of programs, as evidenced by the slogan “move fast and break things”. Therefore, in the domain of Web programming, there is a tension between productivity and quality in the choice of languages.

Many startups love Ruby because of the productivity gain in using Ruby on Rails, which is enabled by the expressiveness of Ruby and its succinct syntax. Now statically typed languages catch up with light-weight web frameworks, and Ruby gradually loses traction. Twitter’s migration from Ruby to Scala created a crisis for Ruby. Now Ruby 3 also embraces a static type system, but the incentives to move to Ruby are not as strong as before.

The Health of Languages

The quality of programs — e.g., reliability, performance, maintainability, security — depends not only on the language, but also on the idiomatic code patterns advocated in the community by mainstream frameworks, libraries, and tutorials.

For language designers, there is a always a tension between the concern for quality of programs and the concern for productivity of programmers (not mention the well-known tension between performance and reliability). Some language features, e.g., meta-programming, may boost productivity but harms readability and maintainability of programs when used without care. As another example, higher-kinded types boosts reliability but compromises readability and understandability as its usage increases.

While it is difficult to come up with a general principle for balancing the quality attributes in designing new language features, special care must be taken when a language feature may potentially undermine all quality attributes of programs. Runtime reflections in Java and runtime metaprogramming in Ruby are two such examples. These language features compromise program performance, program understanding and reliability, thus should be avoided to maintain the health of the language.

The biggest damage to the health of a language comes from bad code patterns that plague the ecosystem — libraries, frameworks, and tutorials. Java reflections is the typical exemple. The two popular Java programming idioms, namely service-provider pattern and dependency injection heavily depend on Java reflection. While such programming patterns cut down syntactic verbosity, they result in compromised performance, maintainability, reliability, security and portability of programs. If most applications, frameworks and libraries are written this way, the future of Java is endangered.

The quality degradation of programs is not only a sad news for the language and its community, but also a bad news for the society, as the programs are underpinning the world. All people in the community — language designers, library authors, teachers, programmers — can make an effort to safe guard the health of the language by avoiding language features and code patterns that compromise the quality of programs.