Friday, May 25, 2012

Still Switch

‹prev | My Chain | next›

Ah, Dart. How I missed thee.

It really is a shame that there a no paying jobs in Dart just yet—it's just that fun (and I'm not just saying that because I'm writing the book). Thankfully, I have at least a few days to play with it again and the built-in excuse that I need to sanity check facts for the book.

Last night I was able to get the Hipster MVC library updated to work with the latest SDK in relatively short order. With nothing breaking, I can now move on through the language specification to see what else may have changed.

I note that the switch statement changed. Way back in March, I decided that the old implementation was not for me. Mayhaps it is now.

The code that I tried to switch mapped keyboard events to directions in a simple Dart animation:
attachMover(me, context) {
  // Move on key down
    add((event) {
      String direction;

      if (event.keyCode == 37) direction = 'left';
      if (event.keyCode == 38) direction = 'up';
      if (event.keyCode == 39) direction = 'right';
      if (event.keyCode == 40) direction = 'down';

      if (direction != null) {
        draw(me, context);

  // ...
Back in March, the best I could do was:
   switch(event.keyCode) {
        case 37: direction = 'left'; break;
        case 38: direction = 'up'; break;
        case 39: direction = 'right'; break;
        case 40: direction = 'down'; break;
The combination of the direction assignment and the break for each case was enough to turn me off.

Ideally, I would like the switch statement to return the cased statement:
      direction = switch(event.keyCode) {
        case 37: 'left';
        case 38: 'up';
        case 39: 'right';
        case 40: 'down';
Failing that, I might settle for a simple assignment statement:
      switch(event.keyCode) {
        case 37: direction = 'left';
        case 38: direction = 'up';
        case 39: direction = 'right';
        case 40: direction = 'down';
Sadly, not much has changed. In particular, if I remove the break statements, I am greeted with a very detailed stacktrace:
Exception: 'file:///home/chris/repos/dart-book/book/includes/animation/main.dart': Switch case fall-through at line 70.
Stack Trace:  0. Function: 'FallThroughError._throwNew@127eafe4' url: 'bootstrap' line:464 col:178
 1. Function: '::function' url: 'file:///home/chris/repos/dart-book/book/includes/animation/main.dart' line:70 col:9
 2. Function: '_EventListenerListImpl@33cc944a.function' url: '/mnt/data/b/build/slave/dartium-lucid64-inc/build/src/out/Release/obj/gen/webkit/bindings/dart/html/dartium/EventTarget.dart' line:16 col:72
Well, at least it fairly explicit that the break statements are required to prevent said fall through.

Reading the spec a bit closer, it seems that the change was that the case value needs to be of the same type. That has no effect on my code since all of my cases are integers (37, 38, 39, 40).

Bah! I'll not be spending any more time on switch. But I do take some time to make the resolution of direction a little cleaner:
attachMover(me, context) {
  // Move on key down
    add((event) {
      String direction = keyDirection(event.keyCode);
      if (direction == null) return;

      draw(me, context);

// Sadly hash literals are still not compile-time
// constants
HashMap<int, String> _dir;
String keyDirection(int dir) {
  if (_dir) return _dir[dir];

  _dir = {};
  _dir[37] = 'left';
  _dir[38] = 'up';
  _dir[39] = 'right';
  _dir[40] = 'down';

  return _dir[dir];
And I still have my little canvas experiment working and the red square "avatar" responding to arrow key input:

Tomorrow, I will continue to root through the the updated language spec to see if there is anything that I might have missed while I was away.

Day #397


  1. You can use some magic for Map ;)

    var direction = {
    '37': 'left',
    '38': 'up',
    '39': 'right',
    '40': 'down'

    1. Good point.

      I actually spent a good deal of time trying to get that working. I'm a bit annoyed that hash literals can't have integers for keys. Also, I got obsessed with only instantiating the hash once. In the harsh light of day that's premature optimization at it's finest.

      In the end that's much better than my silly indirection solution. Thanks!