@script, annotation for the win

While everyone is fawning over Angular 2.0, it isn't something we can really use for a while. But Tracuer and @script are here, and--as long as you support IE9 and up--they are here for you today.

The Angular team published a playground for @script: https://github.com/angular/atscript-playground


So why is annotation-oriented programing so much win?

The quick answer is meta programing. Buzz word alert: The basic idea is that you can mark up some object in your code with additional meta-information. And the cool part: parse that mark up at runtime to give your application additional intelligence.

But lets take a quick look:

// An annotation class that defines an animal
class animal {  
  constructor(sound) {
    this.sound = sound;
  }
  speak() {
    console.log(this.sound);
  }
}

An annotation is really just the instantiation of some class that can be bound to an 'annotations' property on the target class. The above code created an annotation class called "animal." When instantiating a class, we can create animal with a custom sound. As the example bellow shows, the @script annotation syntax allows us to attach the annotation class of "animal" to any classes we create like "cow" or "dog" targets.

// Create a cow class an annotate it with a cow sound.
@animal('Mooo')
class cow {  
}

// Create a dog class and annotate it with a dog sound.
@animal('Woof')
class dog {  
}

This is @script transpilation; the @animal('Woof') actually translates to the following JavaScript.

var dog = function dog() {};  
($traceurRuntime.createClass)(dog, {}, {});
Object.defineProperty(dog, "annotations", {get: function() {  
  return [new animal('Woof')];
}});

After the classes are marked up with annotation, a new property, 'annotations,' becomes available on the class object. It is an array, allowing for multiple annotations to be applied to a class.

cow.annotations[0].speak() //=> Mooo  
dog.annotations[0].speak() //=> Woof  

This is nothing revolutionary, but it does create a great convention, allowing us to write code that describes itself to itself. Lets take a look at a way that this can be consumed. In the code example, lo-dash, it is used for writing functional code, I am a lambda whore.

_.each([cat, dog, table], c => {  
  var noop =  { speak : () => {}};
  (c.annotations || [ noop ])[0].speak();
  });

Each loop can process the individual classes for the annotation property. In more complicated workflows, this can take into account the different annotation classes.

Conclusion

You can find running code examples here.

The code example above is not very useful, since any number of polymorphic practices can resolve this problem in much cleaner ways. But it does show how annotations can create behaviors on classes that you may not have the rights to change. Annotation also get out of the way of the implementation, allowing you to attack cross cutting concerns without affecting the annotated class.