Unlike the 1960s, today very few new languages evolve. Those that do are often moulded from an existing form. In earlier days of programming language design, languages were implemented when the complete specifications were designed. Algol 60 evolved through such a specification, and although specific compilers always contained small variations, the core concept was the same. Radical changes to the underlying structures came at broad intervals, say 5-7 years, which allowed the language to attract users.
One of the major problems today is the pace of language roll-out. Good examples are Julia and Swift. Swift was introduced in 2014, upgrading to V1.2 in the same year, and Swift V2 in 2015, and V2.2 in December 2015. Swift 3.0 arrived in Sept. 2016. All this in a little over two years. What’s wrong with this? The problem is that development of these languages has become far too fluid. I understand that modern languages are often behemoths that naturally require tweaking, but sometimes features disappear or are radically altered between versions of a language – and that just shouldn’t happen. Why? Because radically modifying structures in a language on such a regular basis can lead to painful code migration, and frustrated programmers who then have to spend time rewriting code.
Let’s look at a case in point, the Swift string. Strings in Swift are their own entities, for example an empty string can be created in the following manner:
var emptyString = ""
Easy right? It’s also easy to do things with strings. For example:
var string1 = "darth" var string2 = "vader" string1 = string1 + string2 // string1 now contains darthvader
Many would argue this is much nicer than C. The problem lies in Swift’s evolution from V2 to V3, and involves naming conventions. Swift 2 had a number of functions to advance an index to traverse a string, functions like successor() and predecessor(). Okay, so they DO seem verbose. Some would likely argue that succ() and pred() would have been better… but that’s taking us off topic. In Swift V3 these changed. The properties startIndex and endIndex remain the same. Okay, so let’s look at an example:
let sith = "vader" // Swift 2 sith[sith.startIndex] // "v" sith[sith.startIndex.successor()] // "a"
In V3, the functions startIndex() and endIndex() have been replaced by index(after:) and index(before:). So the above code now looks like this:
// Swift 3 sith[sith.startIndex] // "v" sith[sith.index(after: startIndex) // "a"
Which maybe just doesn’t seem as intuitive anymore. Why change it? Anyways the point I’m trying to make is that continuous changes to the structure of a language means that programmers have to constantly migrate code, which is not ideal. The other issue is when does a language become stable? Does it continuously evolve? And what about backwards compatibility?
The truth is, programmers will become very hesitant to write libraries for new languages, if the structure of the language changes too often. It is hard to devote time to an endeavour, only to make the realization that the codebase will have to be deeply modified on a yearly basis.
Here’s a thought. Design a language. Implement the language. Release the language. Let people USE the language for 3-4 years, whilst reviewing what works and what doesn’t. Then make subtle changes, and allow for backwards compatibility.