Monday, February 20, 2012

Dart Iterable

‹prev | My Chain | next›

Up tonight, hopefully a quick exploration of iterators in Dart. Iterators are the mechanism in Dart that allow any object to be used in a for-in block. I do not necessarily think that my ImageCarousel class needs an iterator to do its thing, but it is the most recent collection-like thing that I have to play with, so...

First up, I define the carousel as extending Iterable:
class ImageCarousel implements Iterable {
  // ...
}
To actually implement Iterable, I need to define an iterable() method:
class ImageCarousel implements Iterable {
  // ...
  iterator() => new ImageCarouselIterator(this);
}
That iterator need only define two methods: hasNext(), a boolean method that returns true unless there are no more elements to return, and next(), which return the next element.

In addition to those two methods, I am going to need a pointer, for which I employ the _pos instance variable. I also need a pointer to the object being iterated:
class ImageCarouselIterator implements Iterator {
  ImageCarousel imageCarousel;
  int _pos;

  ImageCarouselIterator(this.imageCarousel) { _pos = -1; }
}
I am really coming around to the this.XXX constructor parameter format in Dart. It is a crazy easy way to say that the first argument passed to the constructor (in this case an instance of ImageCarousel from its iterator() method), should be assigned to the imageCarousel instance variable. In addition to assigning the instance variable, I also initialize the position of the iterator to -1 so that the next element will be the zeroeth of the array in ImageCarousel (ah, Array indexing).

Next, I define the hasNext() boolean function. That is easy enough—as long as _pos is before the last index in the array, there is a next element to be returned:
class ImageCarouselIterator implements Iterator {
  // ...
  bool hasNext() => _pos < lastIndex;
  int get lastIndex() => imageCarousel.length-1;
}
I am also starting to really dig the hash-rocket short hand for function and method bodies—I can skip the return keyword and the curly braces (win, win). Because arrays start at zero, the lastIndex of an array is the length minus 1. I define a getter for this solely to make the hasNext() function easier to read.

Last up, I implement the next() method, which return the element at _pos as well as increments _pos for the next time through. I also have to throw an exception if next() has navigated past the bounds of the object being iterated:
class ImageCarouselIterator implements Iterator {
  // ...
  ImageCarousel next() {
    if (_pos++ >= lastIndex) throw new NoMoreElementsException();

    return imageCarousel[_pos];
  }
}
Again, that lastIndex getter comes in handy. Or at least makes things a little easier on the eye.

One last thing that I need to do is define the [] operator and length methods on the original ImageCarousel class:
class ImageCarousel implements Iterable {
  // ...
  iterator() => new ImageCarouselIterator(this);
  String operator [](i) => image_urls[i];
  int get length() => image_urls.length;
}
Have I mentioned yet, that I really, really like the hash-rocket method notation?

Anyhow, with ImageCarousel now implementing Iteratable properly with a real iteratable() method, I can give it try with a for-in loop in my main() entry point:
main() {
  // ...
  var gallery = new ImageCarousel(gallery_el, urls);

  for (var img in gallery) {
    print(img);
  }
}
And it works! In my console, I see the names of the images printed out:


It is pretty cool to be able to make any object for-in capable. But not as cool as that hash-rocket method syntax. That's just awesome.


Day #302

No comments:

Post a Comment