After a few years of full-time Ruby, the adjustment has been pretty painful. One of my biggest complaints is the verbosity of the static type declarations. Having recently spent some time playing around with Scala, I was incredibly impressed at how much noise can be removed from a statically typed language with a compiler that does good type-inference. The ActionScript compiler does absolutely zero type-inference, and the result makes for really nasty reading.
const keyword. I really appreciate how Scala's
val keyword makes declaration of immutable fields just as terse and clear as the
var keyword does for mutable fields. This is in contrast to Java, where making things immutable requires an extra keyword (
final) that makes code with immutables (i.e., better, safer code) extra noisy, a great disincentive to doing the right thing. Using
const in place of
var in ActionScript is much prettier than the Java way. Unfortunately I quickly discovered a couple of shortcomings in ActionScript "constants" that really bummed me out.
The first issue I ran into very quickly: Whereas Java only allows final variables to be assigned once, it's smart enough to allow that assignment to happen in a constructor. The ActionScript compiler specifically requires them to be assigned at the point of declaration. This means you can't declare a constant field and assign it its value in a constructor, which is the primary reason I'd want constant fields.
const was still good for static constants (obviously) and seemed to be good for locals as well.
The second issue has to do with using
const on locals and led to a pretty painful debugging session. We were taking advantage of one feature ActionScript holds high over Java's head: functions are closures, and closures are handy. I was looping over some data structure using a for loop. Inside that loop I declared a const, then declared a function I wanted for later that used that const. But at the end of the loop all the functions were referring to the last item in the data structure.
Here's some sample code illustrating what I was seeing.
// Maps an array to an array of functions that return // the values from the original array. // But doesn't work! :Array const functions:Array = ; for var i:int = 0; i < itemslength; i++ const item:* = items i; functions i = function:* return item; ; const funcs:Array = identityFunctions"a""b""c"; funcs2; // => "c", as desired funcs1; // => "c", but I wanted "b" funcs0; // => "c", but I wanted "a"
item const is declared inside the loop, it's really scoped to the entire function. It gets assigned a new value on each pass of the loop, so yes, the
const keyword is a bold-faced lie. Apparently the keyword tells the compiler not to let any other code assign to that reference, but it creates a mutable reference just like
var, and in this case it gets repointed several times.
Basically the function definition above compiles into the same thing as this.
// Comes right out and tells you it doesn't work. :Array const functions:Array = ; var item:*; for var i:int = 0; i < itemslength; i++ item = items i; functions i = function:* return item; ;
Certainly it's my bad not knowing that the
for loop doesn't introduce a lexical scope, but it's crazy for the compiler to allow declaration of a const inside a looping structure. If Adobe's really committed to all this static typing and compiler checking hooey, surely they'd agree this is a nasty gotcha that the compiler should prevent.
As far as workarounds, there are several. For the contrived example above, the simplest is to use one of the iteration methods Array has in ActionScript. There the "body" of the loop is a function, so it has its own scope. Here's the cleanest way.
// Actually works. :Array return items mapfunctionitem:*i:inta:Array:* return function:* return item; ; ;