Tesla Languages and Cart Langauges

I notice there are two kinds programming languages

One kind is built to be perfect. It's informed by what came before it, but built from the ground up to correct the mistakes and flaws of past languages. It handles everything in an elegant, consistent way. If it were a car, it would be a Tesla. (Henceforth, I'm calling these Tesla languages)

I think Ruby is the epitome of a Tesla language. Python is pretty close, and Swift also seems to fit in this category. Interestingly, so does plain ol' C.

The other kind is the kind built by slow evolution. The first version was a minimum viable product built to fill a niche, and more features have been piled on with each version. Its design bent itself in knots to try to be compatible with a bunch of ideas that were in vogue at the time, but are now long forgotten. It has many vestigial features from older versions, which are considered very bad practice to use in any new code.

If it was a car, it would be a monstrosity of design which was build in incremental steps by modifying a horse-drawn buggy. It's wheels are tall, thin wagon wheels which are specified to be backwards compatible with wagon ruts which haven't been used for over a century. Its suspension is a nightmare of complexity to try to give it a smooth ride despite the limitations from those wheels. For decades of its existence, it required the ability to hook a team of horses in front if it ran out of gas, and there's still a hitch in front for that exact purpose. The engine protrudes out the back, since the space in the front is occupied by the hitch. (Henceforth, I'm calling these "cart languages")

C++, Javascript, and PHP all seem to be canonical examples of cart languages, and Java is also a pretty good contender.

It's interesting to me because, all else being equal, we would rather program in Tesla languages. Most of the time, we actually end up programming in cart languages. Those are languages which have never asked people to stop what they're doing, start at square zero, and learn something totally new. When they first came out, they established their popularity by being extremely pragmatic. They offered a familiar approach, and just enough features to meet an immediate need. From there, they added whatever features they needed, while being careful to never break backwards compatibility.

This frustrates language purists, but I'm not convinced that it is necessarily a bad thing. Javascript, in particular, seems to have proved that it's possible for a language to grow into a genuinely pleasant language through this incremental process. While maintaining backwards compatibility, it has managed to have a lot of troubled features slough out of common practice. Meanwhile, Python 3 notoriously jettisoned backwards compatibility to fix some longstanding issues and streamline the language, with poor results. It both failed to fix a lot of the quirks of Python that actually bothered people, and ended up dividing the Python community into Python 2 and Python 3 camps. Even now, a decade after the Python 3 release, Python 3 adoption is far from universal. I think this stands as a warning of what can go wrong with attempts to keep a language pure.

On the other hand, one disadvantage I see is that cart languages seem to accumulate long histories. To use them effectively, it becomes important to not only understand their syntax, but to understand how it got to be that way. If I'm a beginner in Javascript, I'm inevitably going to ask "There are like 6 different ways to declare a function in this language. Which one should I use under which circumstances?", and the answer will begin "It's a long story...". C# is a beautiful language which started out as a Tesla language, but it has accumulated more features over the years. Occasionally somebody will ask, "What's this 'delegate' keyword?"

The answer is, again, "It's a long story. See, in modern C#, you can give function pointers a strong type of Action<T1, T2, etc>. But back before 2005, C# didn't have generics. The delegate keyword gave you a workaround to achieve a similar effect, without needing to wrap a whole class around them like you do in Java"

Maybe this is inevitable in any language who's feature set grows overtime. It adds a little to the learning curve for a language, but its worlds better than having the langauge set in stone, never adding any new features.