9 April 2026 · 4 min
Initially, we had languages like Fortran (1957), Pascal (1970), and C (1972). Fortran was designed for number crunching and scientific computing. Pascal was restrictive with respect to low-level access (it was deliberately “safe”, as meant for teaching structured programming). So C won out as a language that allowed low-level/unsafe programming (pointer arithmetic, direct memory access) while remaining general-purpose enough for systems work like Unix. To be fair, Pascal had descendants that are still around, but C clearly dominated.
Object-oriented programming became viewed as the future in the 1980s and 1990s. It turned into some kind of sect.
But C was not object-oriented.
So we got C++, which began as “C with Classes”. C++ had templates, enabling generic programming and compile-time metaprogramming. This part of the language makes C++ quite powerful, but somewhat difficult to master (with crazy error messages).
Both C and C++ became wildly successful, but writing portable applications remained difficult — you often had to target Windows or a specific Unix variant. This was a problem for a company like Sun Microsystems that sold Unix boxes and wanted to compete against the juggernaut that Microsoft was becoming.
So Java came along in 1995. It was positioned as a safe, portable alternative to C++: it eliminated raw pointer arithmetic, added mandatory garbage collection, array bounds checking everywhere, and ran on a virtual machine (JVM) with just-in-time compilation for performance.
The “write once, run anywhere” promise addressed C/C++ portability pain points directly. To this day, Java remains a strong solution for writing portable enterprise and server-side code.
We also got JavaScript in 1995. Despite the name, it has almost nothing in common with Java semantically. It is best viewed as separate from the C/C++ branch. Python is similarly quite different.
Microsoft would eventually come up with C# in 2000. It belongs to the same C-family syntax tradition as C++ and Java, but with support for ahead-of-time compilation in modern .NET. It also allows guarded pointer access within explicitly marked unsafe scopes. At this point, C# can be seen as “C++ with garbage collection” in spirit. It even competes against C++ in the game industry thanks to Unity.
Google came up with Go. It is much like a simpler, modern C: garbage-collected, with built-in bounds checking on slices/arrays, and pointers allowed but without arbitrary arithmetic in safe code (the unsafe package exists for low-level needs).
Later, Apple came up with Swift. It has C++-like performance and syntax goals but adds modern safety features (bounds checking by default, integer overflow panics in debug mode) and uses Automatic Reference Counting (ARC) for memory management. Swift replaced Objective-C but I still view it as a C++ successor.
At about the same time, we got Rust. Like Swift, it drops the generational garbage collection from Java, C# and Go. It relies instead on compile-time ownership and borrowing rules, with the tradeoff that you can leak memory with reference cycles. We also got Zig which makes memory usage fully explicit.
I think that it is fairer to describe Rust and Zig as descendants of C rather than C++. Both are much more powerful than C, of course… and the evolution of programming languages is complex. Still. They are C-like programming languages.
To this day, in much of the industry, the dominant programming languages for performance-critical, systems, enterprise, and infrastructure work remain C, C++, Java, and C#. By the Lindy effect (the longer something has survived, the longer it is likely to continue surviving), these languages, especially C, now over 50 years old, are still going to be around for a long time.
Daniel Lemire, "A brief history of C/C++ programming languages," in Daniel Lemire's blog, April 9, 2026, https://lemire.me/blog/2026/04/09/a-brief-history-of-c-c-programming-languages/.
[BibTeX]
Just for fun let’s ask LLMs 🙂
Question: Is rust more like C or C++?
Shortened answers:
gemini:
“The short answer is that Rust is mechanically more like C++, but philosophically it shares the “no-nonsense” systems-level DNA of C.
If you’re coming from C++, you’ll recognize the power; if you’re coming from C, you’ll recognize the performance—though you might find the syntax a bit “loud” at first.”
Claude sonnet 4.6
“Rust is more like C++ in several meaningful ways, though it shares C’s philosophy in others.”
chatgpt:
“Rust sits somewhere between C and C++—but it’s closer to C++ in philosophy, and closer to C in simplicity of abstraction (depending on how you use it).”
chat.qwen.ai:
“Rust is generally considered closer to C++ in terms of language design, feature set, and intended use cases, but it’s fundamentally different from both due to its compile-time memory safety guarantees.”
> We also got Zig makes memory usage fully explicit.
Some words got lost
Thanks for the criticism.
JavaScript has a lot of syntax in common with C, though — especially its for-loop syntax, curly brace syntax, semicolons, and operator syntax (triple-equals excepted of course). I’ve always thought of JavaScript as inspired by C and AWK.
C++ is always 🔥🔥
I’ve been struck by how many languages have had types added. C’s predecessor B (heh) and BCBL had one type (machine words). (It looks like you weren’t focusing as much on interpreted languages, but for those, Python has added optional type annotations, and TypeScript evolved as a typed version of JavaScript).
Of the compiled languages you mention, I’m also struck by how many (C++, Java, and C#, I think) have had parameterized types / generics added. (It looks like Go started out with some builtins with parameterized types, but only added user-defined parameterized types later.)
I guess types (and parameterized types) add some complexity; but this seems like another data point in favor of them being useful…
I am not sure that Go started with parametrized types ?
(In the above, “BCBL” should be “BCPL”.)
Yup, you’re right; generics were added to Go in
release 1.18.
According to Gemini, Go has always had _some_ builtins with type parameters: slices ([]T), maps (map[K]V), and channels (chan T), along with functions, of course. (https://go.dev/blog/why-generics mentions slices and maps).
For that matter, I guess C’s function and pointer types are “parameterized types”; but I wouldn’t count them, as those are language built-ins…
(In the above, “BCBL” should be “BCPL”.)
Yup, you’re right; generics were added to Go in
release 1.18.
According to Gemini, Go has always had _some_ builtins with type parameters: slices ([]T), maps (map[K]V), and channels (chan T), along with functions, of course. (https://go.dev/blog/why-generics mentions slices and maps).
For that matter, I guess C’s function and pointer types are “parameterized types”; but I wouldn’t count them, as those are language built-ins…
That first sentence nicely ignores Lisp, from 1958. I’m reminded of a passage from “The UNIX-HATERS Handbook” that mocks this idea of “general-purpose” meaning UNIX.
It’s worth pointing out that Alan Kay “invented the term object-oriented, and I can tell you that C++ wasn’t what I had in mind”. It’s also worth pointing out how James Gosling created Java with the idea that C++ language programmers couldn’t be convinced to use a good language like Lisp, but Java could get them closer to it.
I view all of these languages as C-flavoured ALGOL clones. The Pascal flavour is much nicer; I notice no mention of Ada anywhere, which addressed every issue with Pascal and many more found elsewhere. Ada was created for military applications, but these days defense contractors have learned it’s more profitable to use the C++ language and keep charging for endless “fixes” that never actually work, as in what I’ve read about the F35 fighter jet.
By the Lindy effect, Lisp will outlive all of these languages. For that matter, APL is from the late 1950s to early 1960s, and better matches SIMD hardware and other kinds of accelerators than any of these languages. Languages which don’t base their entire semantics around existing hardware, while simultaneously using only the vaguest terms to describe it, will outlast those languages which do.
That first sentence nicely ignores Lisp, from 1958. I’m reminded of a passage from “The UNIX-HATERS Handbook” that mocks this idea of “general-purpose” meaning UNIX.
It’s worth pointing out that Alan Kay “invented the term object-oriented, and I can tell you that C++ wasn’t what I had in mind”. It’s also worth pointing out how James Gosling created Java with the idea that C++ language programmers couldn’t be convinced to use a good language like Lisp, but Java could get them closer to it.
I view all of these languages as C-flavoured ALGOL clones. The Pascal flavour is much nicer, I notice no mention of Ada anywhere, which addressed every issue with Pascal and many more found elsewhere. Ada was created for military applications, but these days defense contractors have learned it’s more profitable to use the C++ language and keep charging for endless “fixes” that never actually work.
By the Lindy effect, Lisp will outlive all of these languages. For that matter, APL is from the late 1950s to early 1960s, and better matches SIMD hardware and other kinds of accelerators than any of these languages. Languages which don’t base their entire semantics around existing hardware, while nevertheless using only the vaguest terms to describe it, will outlast those languages which do.
I used the wrong e-mail address at first, but my comment stuck waiting in the moderation queue is better than this one, I now remember. Just delete this comment and this response, I suppose. I tried to correct the issue of a comment stuck in the queue, but now I’ve caused this inconvenience, and I apologize for that.
Where does something in infancy (like Julia) fit in all this?