Classes, static properties, and inheritance in Coffeescript
17 March, 2012 Leave a comment
I fear the documentation for coffeescript does not really explain the way that static and instance members work terribly well. So, I’ve put together this rough guide to classes in coffeescript
For this set of examples, I’m going to use my standard class diagram that you may have seen on other blog posts:
Creating a class
To create a class you simply write
However, the way coffeescript works is that class will only be accessible to other things in that script. The command line utility does allow lots of files to be joined together so that may not be such an issue for the most part. However, if you want your class accessible on the page you are going to have to make it globally available in which case you will need to attach it to the
window, like this:
The class constructor
At its simplest the constructor can be as simple as this:
class Animal constructor: ->
The above construct takes no arguments and doesn’t do anything. There is no body. Note, that since coffeescript has significant white-space the constructor method has to be indented. To ensure that it is empty, don’t put the next line of code in at a greater indent depth that the word “constructor”
If the constructor doesn’t need to do anything you can leave it out. If you do need to initialise things then you can. For example, let’s say we want each animal to know its date of birth, we can do this
class Animal constructor: (dateOfBirth) -> @born = dateOfBirth
The @ symbol is a shorthand for
this. However, there is an even quicker way of doing this. If your argument is simply going to be assigned to an instance variable, then you could do this instead:
class Animal constructor: (@born) ->
This is one area I find somewhat confusing. If you want to declare a static field on a class, you prefix it with the @ symbol, as if you are creating a short hand for this. Which is, in fact, what you are doing.
class Animal @population : 0
In the context of the class, the use of this is correct. You are operating int he context of an object of type class. Not an object of an instance of that class. If that makes sense. Essentially, the class itself is an object.
So, if you want to use this static variable on the class you could do something like this
class Animal @population : 0 constructor: (@born) -> Animal.population += 1
And from outside the class, you similarly reference the class itself. For example:
(new Animal 'Today') for count in [1..10] currentPopulation = Animal.population
Similarly, static methods on the class are prefixed with the @ symbol. For example
@resetPopulation: () -> Animal.population = 0
And called on the class, rather than an instance. Also remember that if the method has no parameters, you need to include the parenthesis in the call, otherwise it gets itself in a bit of a twist. e.g.
To inherit from a class you simply extend the base class. For example:
class Mammal extends Animal
If your base class has a constructor then it will be called automatically when you instantiate the derived class. However, if you need to add a constructor of your own to the derived class you must remember to call the base constructor manually otherwise the base construction won’t happen as you expect.
class Animal @population : 0 constructor: (@born) -> Animal.population += 1 @isMulticellular = "no" console.log 'Animal constructor called. Population is '+Animal.population class Mammal extends Animal constructor: (born) -> super(born) @isMulticellular = "yes" console.log 'Mammal constructor called.'
If you note, the call to
super (to call the base constructor) happens first. This is generally what happens in many object oriented languages when constructing classes that have inheritance. The base parts of the class are constructed first. This gives the derived class access to the fully constructed base parts before it does its part. However, you are free to put the call to
super anywhere in the derived class’s constructor.