Here's a ruff list of requirements for the ideal programming language that I came up with:
- has only a few built-in features so that it con be customized for different domains
- uses the same core syntax as a basis for all kinds of third-party supplied DSLs
- allows much better tool-supported factoring than any current tool for any current language provides
- allows IDEs to show the code in different views, rearranging methods, even graphical and tabular representations (see also light table and subtext)
- can scale from being a scripting language for a third-party module up to writing your own DSLs and modules to be used by others
- allows literate programming, support for verification, and also tests. IDEs should understand the verification annotations (such as preconditions, postconditions, invariants) to point out possible errors and better support refactoring.
- is explicit. I think that languages with implicit type conversion, implicit defaults, and other automagical things scale badly, because in a larger program, you'll have a mix of implicit and overwritten stuff and need to keep track of when the defaults are used or what else happens "behind the scences". integrating the language with the IDE means that the defaults can be put into new programs and modules by the IDE thus keeping the advantage of quickly starting a project but also gaining the advantage of staying agile by always seeing where everything comes from and being able to change it just right there.
Interestingly, tool support for different views and verification and flexibility to create DSLs all require that the core language has as few features as possible!
Even more interestingly, as I read Fred Brooks famous essay on "no silver bullet" again, I was easily convinced that new programming languages don't actually make that big of a difference in programmer productivity. Basically, there's been nothing really new since Smalltalk and ML! On the other hand, Brooks convincingly argues that the fastest way to write a software is to not write it at all, but to buy it! Or more generally, reuse existing modules!
While Brook's essay lists a lot of other technologies and methods from which he doesn't expect any significant improvements in productivity, he also mentions three things which actually do have potential in his mind. In short:
- Buy, don't build.
- Develop incrementally from prototypes.
- Find and develop great designers.
Interesting that he mentions incremental development back then in 1986. Agile ain't that new after all! And defining the minimal product hasn't become easier either. It's still one of the essential complexities of software engineering.
Edit: Added "explicitness" in response to Max' comment.
Edit: Added "explicitness" in response to Max' comment.
2 comments:
This was a very interesting read. To tell the truth, I never really thought about it either.
What do you think about portability? Is it fine to re-compile from source for different platforms? Keep in mind that one of the drawbacks of portability is function. If your code runs on ARM tablets, Android phones, Debian machines and Windows, what can it do? Probably not that much.
I think the most important point is that the language shouldn't make everything look like a nail (like C, Java or the abomination that is NodeJS)
A good example (it's not a language though) is .NET since it allows you to code in a functional, pure Haskell-style way (with F#) or in an object oriented way (with C#) and since both run on the CLR they can consume each other. Awesome, right? It's an edge case though.
What I'm missing the most is a language that allows meaningful refactorings that truly improve the code when used wisely. Perhaps this could work like query rewriting in relational theory (while focussing on expressivity instead of performance).
Also, my ideal language has no nulls but something akin to Some/None and does 2-valuated logic (2VL) only.
Hi Max,
thanks for your comment. Especially the last part about the Maybe type and 2-valuated logic. I actually thought about this issue in Java a lot. Currently, I favor the use of @NotNull annotations which are checked by Findbugs, but I also think that it would be so easy to integrate this crucial feature directly into the language. It would be so helpful to have two versions of each type, for example, "String" can't take a null value and *String can take one. You could assign in one direction, but only cast into the other direction, and only call methods on * objects inside of an "if (o!=null) {..}".
As for portability, I totally took that for granted. :-D I think that with the core language being so small, there would be some DSL overlay to do platform specific things like memory management or kernel programming.
As for you CLR argument, I think the same is true for the JVM where we have Java, Groovy, Scala, Jython, and lots more!
Post a Comment