Java has for long been one of the most common programming languages used in information system implementation. However, it is usually a good idea to use many different tools in the implementation of a complex system.
In this article, I present a group of modern programming languages as alternatives to Java. I will also explain why it makes sense to not commit to one programming language for the entire implementation of the system, and for what purposes the alternative languages are best suited for.
Choose the programming language best suited for the purpose
Programming language design is about finding a balance between general usability and special needs: A general purpose programming language can be applied to a wide range of problems, but implementing the solution is easier if the language is designed for that particular problem. The more complex the problem is, the more significant the suitability of the programming language for the problem becomes.
The length of the program code significantly affects the quality of a program. A short program is often easier to understand, implement, and expand, and it has fewer errors.
Program length, on the other hand, is affected by the abstraction level of the programming language, which defines how computer details are presented to the user of the language in a simplified way.
Generally, low abstraction level languages give more control to the programmer but require more programming than high abstraction level languages. On the other hand, programming languages allow programmable abstractions that model the problem that needs to be solved. The more flexible the language, the more extensive models of parts of the solution can be made.
Clear abstractions with functional programming
As programs become more and more complex, they require an even higher abstraction level in order to model solutions in a reasonable amount of code. The functional programming paradigm has been found to be a good way to write clearly structured code. Programs are then composed by combining small independent parts – functions. Because the side effects of functions are limited and functions can be combined in multiple ways, functions are reusable.1
Except for Java, most modern programming languages either fully or partly support the functional programming paradigm. In this respect, Java has not kept up with other programming languages.
However, the Java Virtual Machine (JVM), built to execute compiled Java byte code, and the Java ecosystem with its many libraries are still highly valued. The runtime environment of many new programming languages is based on the JVM: It is not worth re-inventing a virtual machine that works well. In addition, this enables the use of Java libraries from the new language.
Examples of modern programming languages
The most significant feature of Scala is the way it combines functional programming and object-oriented programming. Scala's highly developed type system checks the structure of the program during compilation. In addition, Scala includes versatile tools for developing a DSL (Domain Specific Language) that is tailored for a specific problem domain. When using a DSL, the abstraction level is very close to writing in natural languages.
Scala is suitable for the same purposes as Java, such as performance-critical systems. Experienced Java programmers find it easy to start programming in Scala, because the advanced features of the language do not need to be used immediately. Scala is built on the JVM, and calling Java libraries from Scala code and vice versa is easy.
Clojure is also a functional language that runs on the JVM. However, Clojure is a dialect of Lisp, which essentially defines the features of the language: It has a simple, list based syntax, which represents the whole program. Repeated code structures are abstracted with a versatile macro system, which translates the list structure of the program during compilation.
Clojure offers mechanisms for supporting several different concurrent programming styles. Clojure does not have a separate compilation phase to run the program, but while reading the source code, the Clojure interpreter compiles it to a byte code that the JVM understands. Because of its Lisp ancestry, Clojure is a highly expressive and flexible language, but using it efficiently requires a lot of studying. Like Scala, Clojure code can also use Java libraries, and vice versa.
Ruby has picked its object-oriented model from the Smalltalk language and functional features from Lisp. Developing DSLs inside the program is easy with Ruby's dynamic type system. In addition to web applications, Ruby is also well suited for Unix programming, due to its system call layer and extensive collection of libraries. As a program written with Ruby is not compiled, the development and test cycle during implementation is very quick. On the other hand, the runtime performance of a Ruby program is worse than the performance of a similar program written with a compiled language. There are many different implementations of the runtime, and one of them, JRuby, is based on the JVM.
Erlang is designed for fault tolerant distributed systems with high requirements for parallel execution. In terms of syntax structure, Erlang is a simple functional language, which like Scala and Clojure also avoids side effects. But Erlang's real stake is in its light process model and message passing paradigm. Erlang also offers process monitoring and distribution included in the implementation of its virtual machine. In addition, Erlang's standard library OTP (Open Telecom Platform) includes several solutions to the needs of distributed systems. Erlang is well suited for background components of complicated systems, to take care of message passing or persistence, for example.
Use the right tools for the different parts of the system
All of the programming languages described above can be considered modern, even though only Scala and Clojure are new. The active communities around the languages are further developing the languages, and as functional programming has become more popular, the languages have also gained new supporters.
A carpenter uses many different tools to complete his work, because one tool is not good for all tasks. This is how it should be in software development, too. A modern information system is often so complicated that one language is not suitable for implementing all parts of the system. Each part should be implemented with a language that is most suitable for it.2 An appropriate language solves problems more naturally and with less code than a less suited language. In the end, the quality of the code written affects the quality of the entire information system.