I'm right with Sweeney on this. What we really need is a language that allows highly expressive compile-time contracts to be established. The DBC model is well known to be extremely effective (some might say invaluable) when working on large-scale systems, so why do we only have obscure, unpopular languages (Eiffel, et. al.) that understand the notion?
I'd love to see a language with the library support and rapid-development potential of the .Net family, but with the contract expressivity of something like Eiffel. Contracts are easy to verify at compile-time in many cases, and run-time contract violations are beautifully easy to track and catch. Type-level contractual semantics in a high-level language would totally remove an entire category of run-time bugs, like out-of-bounds array access.
Really IMHO the problem is that languages are not really expressive enough about abstract semantics. We've got great tools for expressing
technical semantics (like "this number requires 16 bits of storage and is always positive") but that's a weak basis. DBC is just one of dozens of areas where the expressivity of most languages in the abstract layers is pathetic.
Unbounded array access should be easy to catch, sure. But in my view, this should be causing a build failure, too:
int milliseconds = timeGetTime();int playerhealth = milliseconds;
I'd love to be able to write code like this, and have it enforced at compile time:
DataType milliseconds Basis:Integers Storage:WhoCaresDataType hitpoints Basis:Naturals Storage:WhoCaresDataType flatpercentage Basis:Naturals Storage:WhoCares Validation:{x < 100}DataType somebitmask Basis:BitField Storage:Bits32
Assigning a milliseconds value into a somebitmask variable should die at compile time. Tossing 120 into a flatpercentage should die as soon as possible (compile time if it can be statically evaluated, runtime otherwise). Trying to assign the result of a hitpoints function into a flatpercentage should vomit at compile time.
Of course, that brings up another question: what if we need to convert between these things? In pretty much any nontrivial application that's going to be a real need. So we do something like this:
DataType inches Basis:Integers Storage:WhoCaresDataType centimetres Basis:Integers Storage:WhoCaresConversion(inches i Into centimetres c) { i = c / 2.54 }Conversion(centimetres c Into inches i) { c = i * 2.54 }
The compiler should be able to do simple chaining of these as well. If I have a centimetres to kilometres conversion, and an inches to centimetres conversion, and code implicitly asks for a munging between inches and kilometres, the compiler should
in most cases be able to construct a graph that reveals the appropriate chain: inches -> centimetres -> kilometres and then invokes that chain transparently. Maybe if the chain is really long it throws a warning and says "maybe there's a smarter way to do this." Maybe it caches the chain someplace and optimizes it separately (noting that certain trivial algebraic manipulations can be done to get a direct conversion from inches to kilometres).
Damn, that'd be a nice world to live in...
Parallelism is something I haven't spent much time worrying about yet, although in another year or so I'll probably have some opinions. It sounds like Sweeney has some good thoughts on the subject, but I have a feeling there are a lot of alternatives that need to be explored. Language expressivity of abstract notions is currently poor in general; expressivity of concurrency possibilities barely even exists.