Private Members In CoffeeScript

I’m a big fan of CoffeeScript. I find it to be more expressive and less clunky than regular JavaScript, plus it makes it easier to extend objects and emphasises lambdas. However, CoffeeScript partially obscures the native closures in JavaScript and as a result makes it very difficult to use private variables and methods.

The word ‘private’ is never mentioned on CoffeeScript.org and the CoffeeScript Style Guide suggests that we prefix methods with an underscore in order to declare them as private. Of course, doing this doesn’t really make them private - it just means you are naming them with an underscore.

It is of course possible to declare private members in JavaScript (and CoffeeScript), but the result is very messy - which is why they are often avoided. Let’s look at one way of declaring private members in CoffeeScript:

class Person
  constructor: (@name) ->

  greet: ->
    "Hi, #{salutation()}"

  title = "Mr"

  salutation = ->
    "#{title} #{@name}"

new Person("Bob").greet()       # Hi, Mr
new Person("Bob").title         # Undefined
new Person("Bob").salutation()  # TypeError: undefined is not a function

While the private method and variables is indeed private, our greet method doesn’t work as expected (it returns ‘Hi, Mr’ instead of ‘Hi, Mr Bob’) - the @name property is not available in the private method. If we look at the compiled JavaScript it’s easy to see what the problem is.

var Person = (function() {
  var salutation, title;

  function Person(name) {
    this.name = name;
  }

  Person.prototype.greet = function() {
    return "Hi, " + (salutation());
  };

  title = "Mr";

  salutation = function() {
    return title + " " + this.name;
  };

  return Person;
})();

The two private members can only be accessed within the closure of the Person instance, but because the scope of this is wrong, the private function doesn’t have access to any public instance members - which really sucks. You can get around this by explicitly doing salutation.call(this), but this seems really weird - having to call public and private functions in two different ways seems like a bad idea. Furthermore these private functions will also not be inherited.

The private variables are even worse though. Consider this example:

class User
  name = null

  constructor: (_name_) ->
    name = _name_

  getName: ->
    name

bob = new User("Bob")
bob.getName() # Bob

steve = new User("Steve")
steve.getName() # Steve
bob.getName()   # Steve

What happened? Why do both users suddenly have this same name? This is because the private variables are actually shared between all instances of the User ‘class’. So private variables are basically a no-go.

Bottom line - stick with the convention of naming private members with a leading underscore. Private members just don’t work all that well. Happy coding.