Programming languages (PLs) allow programming computing systems, typically computers. The history of PLs is long, dating from the 1800s in France to the 1900s in England and developing exponentially after the Second World War. Interestingly, while hundreds if not thousands of PLs have been invented since (between 700 and 9,000 depending on the sources), belonging to many different families, there’s been a convergence, a cross-fertilisation, among PLs in recent years. In the following, I briefly recall the history of PLs, present today’s main PLs, and discuss how I see them converging into the “Pythonisation of Java”.

A Brief History of Programming Languages

The first documented programming language was invented by Joseph Marie Jacquard to control looms [1], patented in 1804 but based on earlier inventions from the 1800s. The Jacquard control mechanism used punched cards to control the looms and allowed complex patterns, such as brocade, damask and matelassé.

Jacquard’s punch cards inspired Charles Babbage who planned to use punch cards to enter programs and data into his analytical engine [2]. Described in 1837, the analytical engine is probably the first real computer because it had separate controls (the “processor”) and memory. It also took as input both formulae (the “programs”) and data.

The analytical engine was the topic of many discussions in Europe, from Italy (1840) to France (1842) back to England. In 1843, Augusta Ada King, Countess of Lovelace, better known today as Ada Lovelace, described how to compute Bernoulli numbers, thus becoming the first computer programmer [3]. She also envisioned applications beyond mere calculations.

The programming of Jacquard’s looms or Babbage’s analytical engine as performed using first generation PLs, i.e., machine languages, literally, because they controlled directly the machines [4]. Second generation PLs, i.e., assembly languages were introduced in 1947 by Kathleen H. V. Booth and Andrew D. Booth to ease the programming with constants, comments, symbolic labels, etc.

Third-generation PLs, i.e., languages that abstract the hardware, were introduced in 1955 when Grace B. Hopper developed FLOW-MATIC [5] and in 1957 when John Backus proposed Fortran to IBM [6]. Many versions of Fortran were developed and even standardised since then, including Fortran 2023! Fortran introduced procedural programming, including the "common" keyword, called "global" in Python, and became the first portable PL in 1962 with FORTRAN IV.

Fourth, fifth, and even sixth-generation PLs exist today [7]. Fourth generation PLs focus generally on databases and reporting, such ABAP, R, or SQL. Fifth generation languages offer problem-solving capabilities, such as Prolog or Geometry Expert. Although there’s no formal definition of sixth-generation PLs, I claim that’s what we should call programming with the assistance of AI chatbots!

Today’s Programming Languages

Since Fortran, many more PLs have been invented, belonging to different families, implementing different paradigms, and proposing various features. There could be between 700 and 9,000 PLs today! [8] The main families include Fortran (obviously!), Lisp (1958), COBOL (1960), and BASIC (1963) [9]. Most (all?) PLs today derive from these precursors or a combination thereof.

Early PLs implemented two distinct paradigms: procedural programming (BASIC, COBOL, Fortran) and functional programming (Lisp). Yet, new paradigms quickly emerged, in particular Simula that, in 1967, introduced object-oriented programming (with the features of classes, objects, and inheritance, among others) [10], then Prolog that, in 1972, introduced declarative programming (with inference and backtracking) [11], then ML that, in 1975, introduced generic programming (with parametric polymorphism) [12], and then Ada that, in 1977, introduced concurrent programming (with tasks, rendezvous, and protected objects) [13].

Data types and type systems were introduced early on with FLOW-MATIC and continued being used (Java), abused (Rust), ignored (Python), and reinvented (TypeScript) since then [14]. Object orientation also spread quickly, becoming the de facto industrial paradigm, epitomised by Smalltalk, the only (?) mainstream (? bis) PL in which everything is an object, systematically and consistently.

While there’s a tremendous number of PLs out there, some PLs are, of course, more popular than others. The TIOBE Index surveys and reports on the most popular PLs [15]. As of November 2024, the top 10 most popular PLs are, in decreasing order, Python, C++, Java, C, C#, JavaScript, Go, Fortran (!), Visual Basic, and SQL. This top ten includes “recent” PLs, like Go (2009) or C# (2000) but also “ancient” ones, like Fortran itself! (Remember, Fortran dates back to 1957!)

Obviously, these languages have evolved, some tremendously. Some PLs attempted to remain backward-compatible with their previous versions, like C++ and Java, which take great pain in ensuring that old code can still compile and run with new compiler versions and virtual machines. Other PLs, like Python [16], had to break backward compatibility, e.g., between Python v2.6 and Python v3.0, to streamline the language, make it safer, etc.

Interestingly, the evolution of PLs could be a topic in and of itself. Some PLs evolve for the best (Python), other can’t evolve and their new version mark their grave (Perl), yet other strive to remain simple and beautiful (C). Finally, and that’s the real topic of this blog post, many converge by borrowing from one another.

Convergence among Programming Languages

Building on previous PLs or borrowing from other PLs is not something new, as the history of PLs shows, e.g., C++ (1983) stems from C (1972), which comes from the long line of B (1970), BCPL (1967), and ALGOL (1960). However, these evolutions were really that, evolutions: new ideas, new features, new syntaxes.

Differently, in recent years, I argue that we’re witnessing a convergence among PLs with top PLs borrowing ideas and features (even syntaxes!) from one another. The changes that tipped me off were in Java, of course!, with JEP-445, JEP-463, JEP-477, and JEP-495. It is now possible to write simple Java programs without bothering with imports, classes, even modifiers and parameters. These enhancements make Java programs look strangely like C or Python programs, don’t they?

Compare Java (and its evolution), with C or Python:

Java Evolutions

C and Python

public class HelloWorld {

    public static void main(String[] args) {

        System.out.println("Hello, World!");

    }

}

 

class HelloWorld {

    void main() {

        System.out.println("Hello, World!");

    }

}

 

void main() {

    System.out.println("Hello, World!");

}

#include <stdio.h>

int main() {

   // printf() displays the string inside quotation

   printf("Hello, World!");

   return 0;

}

void main() {

    println("Hello, World!");

}

print('Hello, world!')

This example is but one example of the many convergences among PLs. I try in the following the summarise the main features exchanged among the few PLs that I know best: C++, Java, and Python. (Besides, Python has now passed JavaScript [17].)

Generics / Templates

Although different in theory, practically generics and templates have similar use cases and are mostly (?) used to declare, define, and use parametrised types. While C++ has had templates since v3.0 in 1991 (with Stroustrup lamenting that they didn’t appear in v2.0, in 1989 [18]), Java didn’t have parameterised types until the introduction of generics in Java 5 in 2004, clearly inspired by their uses and popularity in C++. Similarly, Python introduced type annotations and type variables, which can be used to implement parametrised types in Python 3.5 in 2015.

C++ [19]

Java [20]

Python [21]

List<int> list;

 

list.push(1);

list.push(2);

ArrayList <String> al = new ArrayList<String> ();

 

al.add("Sachin");

al.add("Rahul");

foo = Priority("foo")

bar = Priority("bar", 2)

 

priorities: list[Priority] = [foo, bar]

Exceptions

Java featured first-class exceptions from its inception with a well-defined syntax and semantics, likewise Python. C++ also had exceptions, actually “exception specifications”, from birth but they weren’t well-defined or consistently used [22] to the point that they were removed in C++17 and replaced (?) with std::exception [23], much like Java. Besides, C++ and Python had trouble with chained exceptions and got inspired by Java to solve this trouble and ease developers’ tasks.

C++ [24]

Java [25]

Python [26]

struct chained_exception : std::exception {

    chained_exception( std::string const &s, exception_data *d = NULL )

        : data(d), descr(s) {

throw new ArithmeticException("Top Level Exception.").initCause(new IOException("IO cause."));

try:

    v = {}['a']

except KeyError as e:

    raise ValueError('failed') from e

Introspection / Reflection

Java came with reflection capabilities (introspection, really) thanks to the interplay between its compiler, its class libraries, and its virtual machine [27]. Python similarly came with reflective capabilities, although it looks more ad hoc, with Callable mingling with Class and __new()__ that cannot be overridden consistently [28]. Because it compiles into machine code to be run directly on some hardware, C++ didn’t have introspection / reflection until very late in its life, first (?) thanks to Boost [27] and soon as part of the language, with a proposal to introduce reflection in C++26, which includes the very interesting ^ operator [29].

C++ [29]

Java [27]

Python [28]

constexpr auto r = ^int;

typename[:r:] x = 42;       // Same as: int x = 42;

typename[:^char:] c = '*';  // Same as: char c = '*';

final Class<?> classOfO = o.getClass();

final Field[] fieldsOfC = classOfO.getDeclaredFields();

for (int i = 0; i < fieldsOfC.length; i++) {

    final Field field = fieldsOfC[i];

    field.setAccessible(true);

    System.out.print('\t' + field.getName());

    System.out.println(" = " + field.getInt(o1));

}

class ReferenceCountingMetaClass(type):

    def __init__(self, name, bases, namespace):

        self._instances = 0

 

    def __call__(self):

        newInstance = super().__call__()

        self._instances = self._instances + 1

        return newInstance

 

    def getNumberOfInstances(self):

        return self._instances

Conclusion

I think that we live in interesting times in which PLs are converging and PL designers find clever ways to offer the best of all worlds in their PLs. Still, PLs retain their main characteristics, due to their origins and main paradigms: while Python remains simple and dynamically typed, Java stay true to its strongly-typed, object-oriented origins, while C++ keep its low-level and detailed capabilities.

PS. If you know of other examples of convergence between PLs, especially between C++, Python, and Java, please let me know! (I’ll give all the credit of course!)

PPS. If you don’t mind burning 1-2 acres of trees, you can also ask ChatGPT “What features did Python 3 (in comparison to Python 2) borrow directly from C++ or Java?” or similar questions for C++ and Java.

References

All Web sites were last accessed on 24/11/11.

[1] https://en.wikipedia.org/wiki/Jacquard_machine

[2] https://en.wikipedia.org/wiki/Analytical_engine

[3] https://en.wikipedia.org/wiki/Ada_Lovelace

[4] https://en.wikipedia.org/wiki/Programming_language

[5] https://en.wikipedia.org/wiki/FLOW-MATIC

[6] https://en.wikipedia.org/wiki/Fortran

[7] https://en.wikipedia.org/wiki/Programming_language_generations

[8] https://devskiller.com/blog/how-many-programming-languages/

[9] https://www.researchgate.net/publication/268277381_Selection_of_computer_programming_languages_for_developing_distributed_systems/figures

[10] https://en.wikipedia.org/wiki/Simula

[11] https://en.wikipedia.org/wiki/Prolog

[12] https://en.wikipedia.org/wiki/ML_(programming_language)

[13] https://en.wikipedia.org/wiki/Ada_(programming_language)

[14] https://www.sciencedirect.com/science/article/abs/pii/B9780444529374500095

[15] https://www.tiobe.com/tiobe-index/

[16] https://stackoverflow.com/questions/9066956/why-is-python-3-not-backwards-compatible

[17] https://www.theregister.com/2024/11/05/python_dethrones_javascript_github/

[18] https://belaycpp.com/2021/10/01/history-of-c-templates-from-c-style-macros-to-concepts/

[19] https://gist.github.com/unreadable/fcf83725fb80a6790a43426940644523

[20] https://www.geeksforgeeks.org/generics-in-java/

[21] https://stackoverflow.com/questions/43168350/python-equivalent-for-cs-generic-listt

[22] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0003r0.html#2.0

[23] https://www.reddit.com/r/programming/comments/pdmncd/c_exception_handling_is_a_billiondollar/

[24] https://stackoverflow.com/questions/3543725/should-exceptions-be-chained-in-c

[25] https://www.baeldung.com/java-chained-exceptionst

[26] https://stackoverflow.com/questions/16414744/python-exception-chaining

[27] https://www.ptidej.net/tutorials/javareflection

[28] https://www.ptidej.net/tutorials/pythonpitfalls

[29] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2996r3.html

Image credit: https://www.meme-arsenal.com/en/create/meme/1915974