On November 2nd, 2011, Gilad Bracha gave a talk at Stanford University on Dart, Google’s new web programming language:
A Walk on the Dart Side: A Quick Tour of Dart
The talk is over an hour long but worth watching. The most controversial part of Gilad’s talk is about the role of types in Dart. Dart’s types are optional and treated as annotations, which do not affect runtime behavior. In other words, Dart is a dynamic language with optional types. Gilad acknowledges that you can write absurd code in Dart that still runs. But, he argues, you can also write nonsensical code in languages with mandatory types by using casts. Types do not guarantee correctness of code, he insists. Gilad adds that types are still useful for documenting code. Just remember that in Dart it does not matter whether you use types, or not. The compiled program will run the same.
Not enforcing any type consistency and treating types only as comments for documentation purposes may sound like playing tennis without a net and I am wondering: Why not? You would certainly see more interesting games!
To me optional types started making more sense after reading Dart’s Language Reference, which explains optional types in the context of two development modes:
Dart programs may be executed in one of two modes: production mode or checked mode. In production mode, static type annotations (13.1) have absolutely no effect on execution. In checked mode, assignments are dynamically checked, and certain violations of the type system raise exceptions at run time.
This sounds familiar. In fact this reminds me on how asserts work. You get errors in debug (checked) mode but asserts get stripped out in release (production) mode. If your code runs without any errors in debug mode you should be fine in release mode. I can see how you could do the same with types.
Let me try to translate this idea into an ActionScript example.
ActionScript is in a way a dynamic language with somewhat optional types. In general ActionScript encourages using types:
var sprite: Sprite = new Sprite(); sprite.foo();
The last line triggers a syntax error at compile time, because there is no “foo” method in Sprite:
1061: Call to a possibly undefined method foo through areference with static type flash.display:Sprite.
Types can be optional as this example shows. Let’s assign sprite to an Object, which is by definition dynamic:
var sprite: Sprite = new Sprite(); var spriteObj : Object = sprite; spriteObj.foo();
You won’t get a syntax error at compile time here. But at runtime you’ll get an error complaining about “foo” not being a Sprite method:
ReferenceError: Error #1069: Property foo not found onflash.display.Sprite and there is no default value.
Finally, what happens if you call a non-existing function on an Object?:
var obj : Object = new Object(); obj.foo();
You won’t get a syntax error at compile time. But at runtime you’ll get this error:
TypeError: Error #1006: foo is not a function.
All three examples yield the same results in debug and release:
|Syntax error #1061||Syntax error #1061|
|Runtime error #1069||Runtime error #1069|
|Runtime error #1006||Runtime error #1006|
Now, if we applied Dart’s idea of checking types only in debug mode, we would end up with this interesting table (differences in red):
|AS3 with “Dart rules”||Debug||Release|
|sprite.foo()||Syntax error #1061||Runtime error #1006|
|spriteObj.foo()||Runtime error #1069||Runtime error #1006|
|obj.foo()||Runtime error #1006||Runtime error #1006|
To be honest, I don’t think this is such a bad idea considering that throwing one error in all three cases in release mode would most likely open up new opportunities for performance improvements.