Monday, December 30, 2013

Adding Getters and Setters to a Ball of Yarn

That doesn't sound very useful. But you know what does? Adding getters and setters to a coffee-script class - after all, typescript has them, and I want to have similar functionality in my coffee-script.

Getters and setters are implemented using the Object.defineProperty method. We could implement each property with a call to this method, but I don't want to type a bunch of cruft to define each class property. So lets do it meta - after all, coffee-script IS javascript!

Function::get = ($def) ->
  $name = Object.keys($def)[0]
  Object.defineProperty @::, $name, {get: $def[$name], configurable: yes}
Notice that I've augmented the Function object (:: is coffescript notation for prototype).  This will add a get method to all functions, and in coffeescript a class is a function. We can define set the same way:

Function::set = ($def) ->
  $name = Object.keys($def)[0]
  Object.defineProperty @::, $name, {set: $def[$name], configurable: yes}
But what does that get us? Lets look at an implementation:

class HeartOfGold

  _answer: 0

  @get answer: -> @_answer
  @set answer: (value) -> @_answer = value

Inside of a class definition, but outside of a method scope, @ (this) refers to the class. So we are calling the get method of the class that we defined earlier, to define a getter on the class.

And, if we explicitly invoke the super object, we can inherit the new attributes:
class Zaphod extends HeartOfGold
  # Explicit access to super is used to access property behavior
  @get answer: -> Zaphod.__super__.answer * 2 * Math.PI
  @set answer: (value) -> Zaphod.__super__.answer = value
  constructor: (value) ->
    @answer = value
meaning_of_life = new Zaphod(6.684507609859605)
console.log "Zaphod says that the meaning of life, the universe, and everything is "+meaning_of_life.answer
Run like this -
$ coffee heartofgold
Zaphod says that the meaning of life, the universe, and everything is 42
Now aren't we glad we didn't turn into a big ball of yarn!

(updated: to use google prettify rather than embedded gists. It makes it easier to focus on the code)

No comments:

Post a Comment