Friday, October 26, 2012

Dart: Lazily Evaluating Static Variables Leads to Wackiness

It is now possible in Dart to initialize top-level (i.e. static) variables using any expression. The expression gets evaluated lazily. When I first heard about this, my instant reaction was fear because laziness and imperative programming don't really get along. At the time, I hadn't seen the blog post where Gilad admitted that plainly.

Hence, I spent a couple hours that night trying to come up with ways this could lead to wackiness. I asked Gilad about it, and he said, "Laziness and statefulness can cause scary problems, I know. You can get into these Hesienbugs, where things only show up when you look, so as you debug the problem disappears."

Just to prove the point, I came up with the following Dart program:

import "dart:io";
import "dart:math";

var varA = changeVarB();
var varB = 1;

int changeVarB() {
  varB += 1;
  return 0;
}

main() {
  print("$varB");
  var seed = new Date.now().millisecondsSinceEpoch;
  var nextBool = new Random(seed).nextBool();
  if (nextBool) {
    varA;  // This looks like a no-op, right?
  }
  print("$varB");
  varA;
  print("$varB");  
}

Can you guess what this prints? Half the time, it prints 1, 1, 2. The other half the time, it prints 1, 2, 2. The first time I print varB, it's value is 1. However, the first time varA is evaluated, changeVarB() gets called (i.e. evaluated lazily). From then on, varB's value will be 2.

Of course, being able to initialize top-level variables to things that aren't constant is really useful, so I'm not sure I'd advocate changing this. Nonetheless, it's something I think you should be careful with.

No comments: