The Artillery Blog

Game Development and Engineering

Working with CoffeeScript: Preserving Class Names

Working with CoffeeScript is a series of short blog posts about working with CoffeeScript every day and sharing the tips and tricks that we've learned.

When working with CoffeeScript you probably have noticed that, in some cases, classes may appear to be named _Class when you inspect them in the Developer Tools. This usually happens when declaring a class as an object property or a when declaring an inner class. For example:

class TopClass
  constructor: ->
    @name = "TopClass"
  instantiateInnerClass: ->
    return new @InnerClass()
  InnerClass: class
    constructor: ->
      @name = "InnerClass"

topClass = new TopClass()
innerClass = topClass.instantiateInnerClass()
# This will output: _Class {name: "InnerClass"}
console.log innerClass

This can be annoying when using the debugger to step through your code because the call site will appear as _Class, which isn't meaningful debugging information.

Let's take a look at the compiled JavaScript:

var TopClass, innerClass, topClass;

TopClass = (function() {
  function TopClass() {
    this.name = "TopClass";
  }
  TopClass.prototype.instantiateInnerClass = function() {
    return new this.InnerClass();
  };
  TopClass.prototype.InnerClass = (function() {
    function _Class() {
      this.name = "InnerClass";
    }
    return _Class;
  })();
  return TopClass;
})();

topClass = new TopClass();
innerClass = topClass.instantiateInnerClass();
console.log(innerClass);

Notice the _Class declaration. This is the default name given to any class when the CoffeeScript compiler cannot infer a name for the class. To give the class a name, you must use the following syntax:

ClassName: class ClassName
  constructor: ->

If we apply this technique to our previous example:

class TopClass
  constructor: ->
    @name = "TopClass"
  instantiateInnerClass: ->
    return new @InnerClass()
  InnerClass: class InnerClass
    constructor: ->
      @name = "InnerClass"

topClass = new TopClass()
innerClass = topClass.instantiateInnerClass()
# This will output: InnerClass {name: "InnerClass"}
console.log innerClass

Which compiles to:

var TopClass, innerClass, topClass;

TopClass = (function() {
  var InnerClass;
  function TopClass() {
    this.name = "TopClass";
  }
  TopClass.prototype.instantiateInnerClass = function() {
    return new this.InnerClass();
  };
  TopClass.prototype.InnerClass = InnerClass = (function() {
    function InnerClass() {
      this.name = "InnerClass";
    }
    return InnerClass;
  })();
  return TopClass;
})();

topClass = new TopClass();
innerClass = topClass.instantiateInnerClass();
console.log(innerClass);

In conclusion, when declaring classes as object properties, always use the following syntax to preserve naming:

obj =
  ClassName: class ClassName
    constructor: ->

It's more verbose, but gives more meaningful information while debugging.

blog comments powered by Disqus