Buckshot Videos

Loading...

Thursday, November 1, 2012

Dart Metadata Is Your Friend

Metadata is a recent feature addition to the Dart language.  The Dart SDK already includes a few metadata tags that (integrated with the Dart Editor) can help you catch common errors, and alert users to deprecated code.  In this post, we'll see how to use the two metadata types included in the SDK: '@deprecated' and '@override'


What Is Metadata?


Metadata is essentially a piece of information that can provide additional context to your code.  This information can be used by tools such as Dart Editor, and eventually by your own code via mirror-based reflection.

According to the Dart Specification "Metadata can appear before a library, class, typedef, type parameter, constructor, factory, function, field, parameter, or variable declaration and before an import or export directive."

Using The Dart 'meta' Library


Since this is a package library, you'll need to add a reference to it in your application pubspec, and then run pub install (see pub.dartlang.org for more information about this process).  Once available, you can import the library like so:

 import 'package:meta/meta.dart';  

Now that the metadata types are in scope for your app, it's time to put them to good use!


Using the @deprecated Metadata Type

Let's say you have a class for a function that you no longer want users of your library to use.  By marking your object with the @deprecated tag, the Dart editor will strike-through any references to it, giving a great visual clue to the developer that they should use a new approach.

First lets look at our function before @deprecated is applied:

Suddenly foo() isn't so cool anymore and we want to let users of the library know about it.  Let's add the @deprecated metadata and see what Dart Editor does:

Notice how Dart editor strikes through not only the implementation function, but also any references to that function.  Neat huh?  The editor also gives other visual clues, such as an informational message and a squiggly underneath the reference.


Using the @override Metadata Type

Now this one I really like, because it's actually helped me catch a few inheritance-related bugs in my code.  Let's look at this example where we have a class Bar which inherits from a class Foo, and Bar wants to override some methods in Foo:


By using the @override metadata type, we can see that the editor is helping us identify a problem in our Bar class, where we have a typo in the override class name.  Notice how we get no help on the 'donothing()' method in Bar, when we probably wanted to override 'doNothing()' in Foo.

In larger, non-trivial applications these kinds of bugs can be nasty to track down, if you consider that this code...

 new Bar().doThat();  

...will happily execute and give you a result of "doThat" from Foo instead of the expected "Do that other thing." from Bar - leaving you with clenched fists and pulled hair as you try to trace down the problem..  In short, using @override every time you expect to be overriding a superclass method will help you avoid a whole class of bugs in your code.

Summary

Dart's metadata functionality is still in early days, but already proves quite helpful when combined with tools such as the Dart Editor.  Liberal use of @deprecated and @override will go along way toward making your code easier to work with and troubleshoot.  Give it a try in your code today and give your feedback to the Dart team.

References:
http://news.dartlang.org/2012/07/draft-spec-changes-for-metadata-in-dart.html
http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.d0rowtffuudf

Friday, October 5, 2012

Common Dart Scenarios for the 'Future' API

A Future<T> object represents a unit of work that will complete at some point in the - you guessed it - future.  I use Futures a lot in my code and I thought that rather than do an exhaustive walk-through of the class itself, I'd share some of the more common patterns and concepts that I often find useful.

In Future Does Not Mean In Parallel

If you come from the .net world, you'll probably have some experience with Task<T> and the whole parallel processing API.  Futures aren't that.  They are more like structured callbacks, which will almost always run in the same memory space and thread as your application.  They won't run in their own threads or multi-core on their own.  If you're interested in parallelism, consider exploring Dart's Isolates API.

Futures Are Not Automatically Asynchronous

At the time of this writing, there is a ticket open in the Dart queue to make all futures asynchronous, but for now what you are about to read remains accurate.

It is important to understand that Futures are not necessarily asynchronous by default. Let's look at this example:
 // This future is not asynchronous and will complete as soon as it is called.  
 Future<bool> greaterThan42(int number){  
   final c = new Completer();  
   c.complete(number > 42);    
   return c.future;  
 }  

This above code is synchronous, in fact you can write it in a much more succinct way using the .immediate() constructor of the Future class:
 Future<bool> greaterThan42(int number) =>  new Future.immediate(number > 42);  

Futures are really most powerful when dealing with asynchronous work, lets use the Timer class to simulate that here:
 Future<bool> greaterThan42(num number){  
   final c = new Completer();  
   
   void doWork(_){  
    c.complete(number > 42);  
   }  
   
   // take 3 long seconds to return our result  
   new Timer(3000, doWork);  
   
   return c.future;  
 }  

The example above uses the Timer asynchronously callback a function after a 3 seconds has elapsed.

A Couple Of Common Future Scenarios

Waiting For One Or More Futures To Complete

The futures API provides a very convenient way to deal with this scenario, in Futures.wait().  Lets see how it works by modifying our greaterThan42 future a bit.
 Future<bool> greaterThan42(num number, int howLongMs){  
   final c = new Completer();  
   
   void doWork(_){  
    c.complete(number > 42);  
   }  
   
   // take 3 long seconds to return our result  
   new Timer(howLongMs, doWork);  
   
   return c.future;  
 }  
   
 main(){  
   Futures  
    .wait([greaterThan42(5, 1000), greaterThan42(100, 3000)])  
    .then((List<bool> results){  
      print(results);  
    }  
 }  

So what is happening above when we send a list of 2 futures into Futures.wait()?  Well, it waits!  It does all the mundane work necessary to be sure that all the futures in the list have completed.  It then itself returns a Future, containing a list of the results returned by the Futures we were waiting on.

The results of running the above code will yield:
 [false, true]  

Similar to this, we often need to iterate over a list of objects, where a method in each object returns a future. Dealing with this in a standard iteration construct won't work cleanly,  because the iteration will continue happily along whether or not our future has completed.  We can use Futures.wait() and a .map() to deal with this nicely:
 main(){  
   Futures   
   .wait(listOfFoos.map((foo) => foo.callFutureMethod()))   
   .then(results){  
     // now we can safely iterate the results of the future calls  
     results.forEach((bar) { // ... });  
   }   
 }   


Working with Futures in Sequence

Often times we want to receive the result of some Future, and then pass that result into another Future.  Do this 4 or 5 times and you get a really nasty scaffolding effect:
 callFutureA()  
   .then((resultA){  
    callFutureB(resultA)  
      .then((resultB){  
       callFutureC(resultB)  
         .then((resultC){  
           print('Kill me now!');  
         });  
      });  
   });  

Fortunately, the Future API gives us a nice way to deal with this as well, with Future.chain().  Future.chain() takes some result and then returns another future, such that you can keep your control flow flat:
 callFutureA()  
  .chain((resultA) => callFutureB(resultA))  
  .chain((resultB) => callFutureC(resultB))  
  .chain((resultC) => callFutureD(resultC))  
  .then((resultD){  
    print('Wait, don't kill me after all!');  
   });  

Furthermore, if you are just doing a simple transforms on a future, you don't have to wrap all of your transformational functions in Futures.  You can use the Future.transform() function to achieve the same result:
 futureA(String foo) => new Future.immediate('$foo A');  
 functionB(String foo) => '$foo B';  
 functionC(String foo) => '$foo C';  
 functionD(String foo) => '$foo D';  
   
   
 main(){  
  futureA('Transform me!')  
   .transform(functionB)  
   .transform(functionC)  
   .transform(functionD)  
   .then((result) => print('$result'));  
 }  

Yields:
 Transform me! A B C D

Now, I could go off on a tangent here about the need for an await keyword in Dart, and how that would make dealing with asynchronous control flows even more simple to work with, but I'll save that for another post (maybe).

Summary

The Future API provides a great way to manage asynchronous coding in Dart.  Smart use of the API will keep your asynchronous code well managed and readable.

Sunday, August 26, 2012

Working With Mirrors In Dart - A Brief Introduction

Mirrors provide a way to perform reflection on your application.  The great thing about mirrors vs traditional reflection in other languages is that they are not intrinsically tied to the object system.  This stratification provides many benefits.  If you want to learn more about mirrors in general, check out this great list of links provided by Gilad Bracha.

Dragons!  The mirror API is still very new and subject to change at any time.  At the time of this writing, it is only supported in the Dart VM (not dart2js).

A mirror is a meta object, that provides information about, and in some cases operations on, objects in a Dart application.  Each type of canonical "thing" in Dart has, generally speaking, a corresponding mirror type.

A listing of mirror types supported by the API.
As you can see from the list above, there is a mirror for just about everything.  Different mirrors provide different kinds of visibility (introspection) and operations.

Mirrors Beget Mirrors

Mirror functions always return another mirror as a result. Even the instantiation and invocation functions will return an InstanceMirror. It is from the InstanceMirror that you can get access to the concrete object from your application.

Perusing Dart With Mirrors

The mirror API allows you to inspect pretty much anything in your application.  At the top level, the starting point for doing so done this way:

 final MirrorSystem ms = currentMirrorSystem();  

I should note there that there is another sibling of currentMirrorSystem() called mirrorSystemOf(SendPort port), which is used to reflect on other isolates, but I won't be covering that in this post.

With this mirror in hand, you can iterate through all the libraries that are currently in scope of your application, iterating through the libraries map will naturally yield LibraryMirror's.

 final MirrorSystem ms = currentMirrorSystem();  
 // Iterating through libraries  
 ms  
   .libraries  
   .forEach((String name, LibraryMirror libMirror){  
      print('$name $libMirror');  
   });  

LibraryMirror, in turn, exposes collections of members, classes, functions, getters, setters, and variables for that particular library.  It becomes trivial then, to drill down to exactly information you need.

Instantiating and Invoking

There are two mirror types in particular that provide a way to instantiate objects and invoke methods:  ClassMirror and ObjectMirror.  In ClassMirror, there is a function called newInstance() which will return a Future<InstanceMirror> object. Lets see how this works:

 #import('dart:mirrors');   
   
 main(){   
  final foo = new Foo();   
   
  //lets get a reflection of foo   
  InstanceMirror fooIM = reflect(foo);   
   
  //now we get to the ClassMirror of fooIM   
  ClassMirror fooCM = fooIM.type;   
   
  //with our class mirror we can create a new instance of foo   
  //(an new InstanceMirror is returned)   
  fooCM   
   .newInstance('',[])   
   .then((InstanceMirror newIM){   
   
      //our concrete instance is now located in newIM.reflectee   
      newIM.reflectee.doSomething();   
   });   
  }   
   
 Class Foo   
 {   
   void doSomething(){   
     print('you did it!');   
   }   
 }   

Running this program will yield:

 you did it!  

Invoking methods is not much more difficult, but there is one area where you will want to pay special attention:  Invocation of instance methods will need to be done on an InstanceMirror, whereas invocation of static methods will be done on the ClassMirror.  Lets try both:

  #import('dart:mirrors');   
  main(){   
  final foo = new Foo();   
   
  //lets get a reflection of foo   
  InstanceMirror fooIM = reflect(foo);   
   
  //now we get to the ClassMirror of fooIM   
  ClassMirror fooCM = fooIM.type;   
   
  //invoke the instance method  
  fooIM.invoke('doSomething', [reflect('hello world')]);  
   
  //invoke the static method  
  fooCM.invoke('doSomethingStatic', []);  
  }   
   
  Class Foo   
  {   
   static void doSomethingStatic(){  
     print('you invoked me and I'm static method!');  
   }  
   
   void doSomething(String message){   
     print('instance method received message $message');   
   }   
  }   

.invoke() also returns a Future<InstanceMirror> on the result of the invocation, if we are interested in the return.  In the example above we aren't.

Also in the example above, we pass a value to doSomething() during the invocation, and we need to wrap it in a mirror using reflect() (the Dart team may do this automatically for us in the future).

Non-final fields, along with explicit getters and setters, also have a similar invocation mechanism, but the calls are made to .getField() and .setField() instead.  More information about these can be found in the ObjectMirror class.

Summary

The Dart mirrors API provides a powerful set of tools for reflecting on your code.  Hopefully this brief introduction to the will help you get started.

Thursday, August 23, 2012

Fun House Of Mirrors

Working feverishly on a version of Buckshot that uses the new #dartlang mirrors API.

Where before you had to pre-register controls to the framework, this version finds and instantiates controls automatically.  All you have to do is import the library with the control in your app, and Buckshot does the rest.  This has the added benefit of preventing registration sequence problems where a control might want to reference another control that hasn't been registered yet.

This branch of the project only works in Dartium at the moment because mirrors isn't yet supported in dart2js, but if you'd like to check out some aspects of how mirrors work, then give it a spin at the link provided below.  All of the included demos work with the mirror-based version.

I have a helper class that provides some utility functions via mirrors here: miriam.dart

Buckshot 'Latest' Branch On Github

Tuesday, June 19, 2012

Two Of My Projects Make the Google I/O Intro To Dart

This is a very comprehensive and well done introduction to Dart by Seth Ladd.  I was pleasantly surprised and honored to see two of my projects listed on the community slide: Buckshot UI and the "Zart" Z-Machine.  

Congrats to all the great community projects that made the video (around minute 34:00)!


Sunday, May 20, 2012

Zart - A Z-Machine Interpreter Written in Dart

My first truly amazing experience in gaming was Zork I, crafted by long defunct Infocom (sad).  Back then, the wow-factor of the cross-platform virtual machine and sophisticated parser was huge.  It seemed like the whole geek-world was giddy with text adventure fever!

This project represents my homage to those days.  It seems somehow appropriate to marry such and old, yet still somehow impressive, virtual machine technology with today's latest and greatest: Dart!  On all counts, it is for me a labor of love.  

Zart is not a port, strictly speaking.  It is written from the ground-up, primarily from the (thankfully) still existing Z-Machine Standards Document.

I present to you Zart, running the public domain version of Zork: Mini-Zork.  Watch out for the grue!

UPDATE: The web demo (link below) now supports "save" and "restore".  It allows only a single save, but hey, not too shabby for a browser app.  The save game remains available even after you close the browser window.



Source Code:  https://github.com/prujohn/zart

Friday, May 4, 2012

I'm A Contributor, And So Can You!

A while back I made a small contribution to the Dart code base (Dart is open source, didn’t you know?). It wasn’t anything spectacular, just a enhanced output for HTML unit tests (source, blog) Eventually, my patch was accepted and is now part of the Dart trunk codebase, which is both personally satisfying and just really cool. More to my pleasant surprise, I found that the Google Dart team added my name to the AUTHORS document in the root of the Dart repository – neat!




This started me thinking about other meaningful ways I could contribute to the project. There were lots of improvements to Dart that I’d suggested over time (all of them awesome), so why not work on one of those, right? As it turns out, this isn’t as easy as it seems. The Dart core code moves fast and furious inside Google – and that’s a good thing. It also means that submitting something truly impactful requires one to keep up with the fast pace of change in the ‘bleeding edge’ branch; not such an easy task. And even if one were able to keep up with the change rate, any patch that would significantly alter the core language would come under heavy scrutiny, and rightly so. Such a contribution might not be considered at all.

After some dialog with Seth and other members of the Dart team on this topic, we (well mostly he) came up with a list of suggestions for folks who want to contribute to the Dart open source project. While some of the suggestions on the list aren’t “core” Dart programming tasks, they are important to the project, and would provide a way for Dart enthusiasts to get their own names listed as a contributor in the Dart AUTHORS document.

It is important to note that the items in the list below are merely suggestions.  You can submit anything you like, and it is highly recommended that you familiarize yourself with the  “How To Contribute - Guidelines” as your first step.  It is also important to note that there are no guarantees that your submission will be accepted.  In fact, you’ll probably go through some stringent, but ultimately satisfying, feedback cycles with the Google Dart team.  I found the process to be both challenging and rewarding.

Contribution Suggestions (see ‘Resources’ below for reference material):

  • Documentation (code docs, updated/comprehensive README’s, etc.)
  • Better build instructions (full walk-throughs for each OS)
  • Better “How To Contribute” docs (full walk-through, step-by-step)
  • HTTPS support for Dart VM
  • Libraries to unify HttpClient and XHR
  • Libraries to unity FileSystem API and the File/Directories form dart:io
  • Unified Logging API
  • Move to true Element constructors in dart:html (from Element.tag(‘div’) to Element.div())
  • Add or update samples (check existing samples first)

So what are you waiting for? Become a Dart project contributor today!

Resources: