First experiment with Dart

I have been playing with Dart for the first time this weekend, and so far I really like it. I made the canonical todo list app (see it here), using a great library called Polymer. Polymer gives you a way to encapsulate style, markup and behavior into your own custom HTML tags which you can recycle and pass around as proper objects. So the 'data model' object which stores an Items "description" and "status"(done/not done) is the same as the HTML object which gets rendered. 

That is worth saying slowly to yourself, because as a JS developer that was totally foreign to me. But it is really natural from any kind of GUI programming standpoint. All you do is add your TodoItem or whatever model to the DOM and it is rendered there by the special tag you've created, in this case it'll show up as a <todo-item> tag. 

Organizationally what this means is that all your components have a .dart file that describes the model and a .html file that has the markup/template for it. WHICH IS AWESOME. One of the worst things about dealing with increasingly complex javascript frameworks is template organization and stuff.

Which brings me to what I really like most about Dart. I can just program. 

Again, I can just program

From a Javascript world, this is amazing. Like, no libraries I have to go get and setup for build systems, dependency management. There is almost 0 boilerplate code. Boilerplate has lost it's offensiveness as a word, because you need so much boilerplate for HTML5 that everyone just assumes that is the way it works. False. Boilerplate code means that you are doing it wrong

Not just the build system either. I don't have to go get jQuery AND underscore AND AND AND just to start programming. The standard library is really, really, really good! The standard library has support for SVG, webGL (great for me!), streams, serialization, see the whole list here

The external library ecosystem might be brand new, but the standard lib is so good that I'm really not hurting that much. And if you really need system, there is always js interop.

There are always a lot of hiccups when learning something new, here is a little list of goods and bads:

  • Documentation is very good, and the IDE helps so much.
  • Love static typing if for no other reason than code completion, not to mention safety.
  • Streams are cool but can be confusing in terms of what is being returned and when. But thats where using an IDE helps because I can just set breakpoints and hover over my variables to see what value they have.
  • Polymer is just awesome. But it seems to still be pretty young and changing very rapidly, which leads me to:
  • Out of date documentation: this is nobody's fault really, but a lot of stackoverflow answers are on out of date versions of Dart, and especially Polymer which has undergone a lot of integration with the Dart standard library recently so there are a lot of wrong code examples with extraneous libraries and names. Just look at the official docs instead, it works.
  • Editor apparently has some strange issues with static file serving, and tends to mess with your paths. This is only important if you are using things like client side routing, in which case just serve them manually from the command line. Other than that, the editor is quite good, if pretty slow at times. 
  • Cascades are really nice, its like chaining on steroids (stole this example from here
  query("#text")
..text = "Click me!"
..on.click.add((Event event){
rotatePos += 360;
query("#text").style
..transition = "1s"
..transform = "rotate(${rotatePos}deg)";
});
  • Got tripped up by the lazy evaluation of maps over lists. applying .map to a list doesn't return a list, it returns an iterable to be evaluated later. 
functionThatTakesAList(List<String> listOfStrings){ ... }

List<String> listOfStrings;

// This will throw an error
functionThatTakesAList( listOfStrings.map(processString) );

// You need to convert it to a list (i.e. evaluate it) first

properList = listOfStrings.map(process).toList();
functionThatTakesAList( properList );
  • Objects that extend PolymerElement don't have a default constructor of the same name as the class. Instead, to create one, you create an element with that tag name... I don't really know why, but you can smooth that over by making a factory of the same name.  It gets a little verbose and repetitive. I'm really not sure I'm doing it right though, I am probably missing something obvious. 
class MenuWidget extends PolymerElement { ... }

...

// This throws an error
MenuWidget menu = new MenuWidget();

// This is correct, assuming your tag name is this
MenuWidget menu = new Element.tag('menu-widget');

// To smooth this over, just put this
// at the end of your class definition

factory MenuWidget() => new Element.tag('menu-widget');

// Of course then you have no constructor params
// so usually I would have
factory MenuWidget({String title, String desc, ... }){
return new Element.tag('menu-widget') as MenuWidget
..title = title
..desc = desc ...;
})
  • I really like the function declaration syntax. It gives you access to optional named or positional parameters and default values! Finally!
// standard function def with optional return type
[optional returnType] funcName(param1, param2){}

// you can put types on anything you want
funcName(String param1, Map param2){ ... }

// named params go inside {}
funcName({String aString, Map aMap}){ ... }
// and get called like this
funcName( aString:val, aMap:val )
// and they are optional this way

// default values work the same way
funcName({String aString:"defaultString"}){ ... }