I am reading through the Swift book, and comparing it to Rust, which I have also been learning over the past few months. As with the other posts in this series, these are off-the-cuff impressions, which may be inaccurate in various ways. I’d be happy to hear feedback! Note, too, that my preferences are just that: preferences. Your tastes may differ from mine. (See all parts in the series.)
I’ve still been (slowly) working through the Swift book and comparing Swift and Rust; I have another draft started which I’ll hopefully finish this week. And I still find the comparison deeply profitable. The two languages continue to evolve in interesting ways, and the comparison is all the more interesting now that Swift is open-source and its future open for community input (just as Rust is).
Something I’ve been thinking about for several months, and which the brief discussion of Swift, Go, and Rust at the end of the latest Accidental Tech Podcast brought back to my mind, is the question of what the next generation of systems-level programming language should be. And my answer is: there shouldn’t be just one. The best possible thing for the space, in many ways, is for there to be a healthy diversity of options and lots of competition in the space. We don’t want to have ten different systems programming languages to deal with, I think—but three or four or five would be much preferable to having one or two (closely related) as we have in the decades of C and C++ dominance.
Don’t get me wrong: both languages (and perhaps especially C) do many things exceptionally well. For all that they are (justly) maligned for some of their problems, the longevity of both C and C++ has a great deal to do with how well they fit the problem domain, and how much they’ve empowered developers to accomplish within that space (which is very, very large).
The problem, though, at least as I see it, is that the existence of only two really serious systems programming languages for the last several decades has led a lot of developers to think that C and C++‘s ways of solving problems are the only way to solve problems. The languages we use shape the way we think about possible solutions, and when a given language doesn’t recognize entire classes of different approaches, that deeply limits developers’ ability to tackle certain issues. (See also the interesting CppCast interview with D’s Andrei Alexandrescu in which he makes similar points.)
The most obvious thing missing from both is the ability to do truly functional-style programming. C of course is also lacking classes and thus is much more difficult to use for any sort of object-oriented programming.1 Neither has anything remotely like Rust’s traits or Swift’s extensions; C++ has only gotten lambdas recently.
All of this comes out to mean that the set of tools available to systems programmer has necessarily been missing any number of things available in languages outside that context. In some cases, this may be a necessary consequence of the kinds of programming being done: when you need totally deterministic memory and compiler behavior, dynamic typing and a non-trivial runtime are simply not options. But in many cases, they are simply a function of the history of the languages’ development and history. Being an ALGOL descendant, and especially a C descendant, means there are some fundamental choices about the language which will differ from those made in a language descended from ML.
All of which is to say: C and C++ have been really useful tools in many ways, but having only C and C++ available for serious systems programming work over the last decades has left many developers blind to or simply unaware of the real advantages other paradigms might offer them.
So going forward, I don’t want there to be a winner in the systems programming space. I’d rather see D, Rust, Swift, Go, and maybe even a few other contenders all stay strong—finding their own niches and continually pushing each other and learning from each other. That will give us a space in which different languages are free to try out different approaches to the same problems, without being tied to the specific constraints faced by other languages. Built-in greenthreading? Go! Hindley-Milner types, memory safety, and zero runtime? Rust! Something in beween, highly expressive and with different type systems and tradeoffs around memory management, etc.? Swift, or D!
Having a robust, thriving set of competitors in the market will be good for the languages themselves. But it will also be good for developers. It will take off some of the blinders that come from a single language (or a pair of very closely related languages) dominating the ecosystem. It will make it likelier that people will be more familiar with different programming paradigms. And that can only be a good thing, as far as I’m concerned.
- Previous: Classes and structs (product types), and reference and value types.
- Next: Properties: type and instance, stored and computed.
It is of course entirely possible to do non-classical OOP; the point is that C entirely lacks language-level facilities for OOP, inheritance, etc.↩