Instance private, class private, package and friends 20

Update: This is flawed. See details at the end.

This post was inspired by a post that Robert Nyman wrote a while back. At the same time I was thinking about how to achieve private fields without the memory issues.

JavaScript does not have private members as understood by a lot of other object oriented programming languages. However it can use closures to achieve the same effect. Below is a very typical code sample.

function Cartman() {
  var secret = 'Tea party';
  this.guessSecret = function(guess) {
    return guess == secret;
  };
}

This is pretty straight forward and works because we define the public method in the scope of the local variable which now works like a private property. There are a pros and cons with this pattern:

Pros: Simple and easy to understand.

Cons: Very memory hungry since every instance needs its own function to encapsulate the local vars.

Therefore most libraries that are object heavy uses a naming convention for private fields. The most common convention is to prefix the field with an underscore.

function Cartman() {
  this._secret = 'Tea party';
}

Cartman.prototype.guessSecret = function(guess) {
  return guess == this._secret;
};

Now all instances can share the methods but we lost the integrity. Anyone can read _secret of an instance.

I’ve been playing around with hybrid models that allows methods to be shared but still allow real private members.

My first idea was to use a closure outside the actual constructor and define a key there. Then basically store the private state in an object that is guarded by that key. This turns out to change the model from instance private to class private. This means that all instances of a class can access the private state of all other instances of that class. Some OOP do this intentionally. Java does this for example.

The code for this quickly gets ugly but below is a working example.

// Define variable outside anonymous block. Will be set inside the block.
var A;
(function() {
  var KEY = {};

  /**
   * Helper function to get the private state object.
   * @param {!Object} obj The object to get the private state for.
   * @return {!Object} The private state object.
   */
  function getPrivate(obj) {
    return obj._getPrivateWithKey(KEY);
  }
  
  /**
   * Store the private state object in a closure.
   * @param {!Object} obj The object
   * @param {!Object} state The state.
   */
  function setPrivate(obj, state) {
    // Add a convenience method.
    obj._getPrivateWithKey = function(key) {
      if (key === KEY) {
        return state;
      }
      throw Error('Permission denied');
    };
  }

  // Set the external variable here.
  A = function (a) {
    var P = {
      a: a
    };
    setPrivate(this, P);
  };

  A.prototype.getA = function() {
    return getPrivate(this).a;
  };
})();

Try it.

This works because the object is associated with the key inside setPrivate using a closure. The function getPrivate which uses the KEY is only visible inside the anonymous function scope and therefore only code inside the anonymous function can get access to the private state.

This actually leads to any code inside the anonymous function being able to see the private state of an object. You can therefore use this concept to allow different classes defined within the same anonymous function scope to see each others private state. This can be treated as a sealed package — a package that cannot be reopened after it has been closed.

We can take this concept one step further and add support for C++ style friends by giving away our key to someone else. Something like:

var A;
(function() {
  var KEY = {};
  A = ...;

  var friendKeys = {};
  A.addFriend = function(id, key) {
    friendKeys[id] = key;
  };

  function getFriendPrivate(obj, id) {
    return obj._getPrivateWithKey(friendKeys[id]);
  }

  A.prototype.accessFriendPrivate = function(obj) {
    return getFriendPrivate(obj).b;
  };
})();

var B;
(function() {
  var KEY = {};
  B = ...;
  A.addFriend('B', KEY);
})();

Try it.

Now instances of A can access the private state of instances of B.

Conclusion

Is this really useful? I would say no. It adds too much boiler plate code without enough real gain. A lot of people try to apply known concepts from languages like Java and apply them to JavaScript. If you really need to be able to hide the state then I would use the instance private pattern first used in this post. It is easy to write and easy to understand and does not have a lot of boiler plate code. However, I would only use it where hiding the state really matters. In most cases it doesn’t. For example, Gmail was written without any true private members. We just use a naming convention.

This also brings up a related topic which is using JS as an object capability language and Doug Crockford made an excellent presentation about this a while back.

Update

henrah pointed out that this model is flawed since the key leaks. Anyone can override _getPrivateWithKey to get access to the key.

  • http://www.aleto.ch chris

    This solves not really what you mention as disadvantage of the straight forwarded approach: for each new instance of A you create a new closure in the ‘setPrivate’ call, meaning ‘obj._getPrivateWithKey = function(key)’ is always a new copy.

  • Pingback: Anecdotes of a Dog Part 6 | Anecdotes of a Dog

  • http://andrewdupont.net Andrew Dupont

    It’s quite refreshing to see someone demonstrate a quirky feature of JavaScript, but ultimately come to the conclusion that it’s simply not worth the effort. Things can be cool but useless. Good job.

  • http://erik.eae.net Erik Arvidsson

    Chris: With the given solution each instance of an object gets 1 closure to hide the state. Compare this with the other solution where you get one closure per instance and method, and these function objects are usually a lot bigger in practice. 2*n vs n*(m + 1) where n is the number of instances and m is the number of methods per object.

  • http://www.aleto.ch chris

    I see, you’re right.

  • Pingback: Ajaxian » Trying to be private in JavaScript

  • henrah

    Another problem with this model is that the encapsulation is relatively easy to break. Even though the value of `KEY` is hidden inside a closure, this value gets passed into the obj._getPrivateWithKey() method every time it is called, and by overriding this method on a single instance of A, you can obtain the key object and gain access to the internal state of all other instances of A.

    I don’t think this is a shortcoming of Erik’s particular example implementation, but rather an inescapable limitation of encapsulation in javascript. No matter how private data is stored, methods on an object need to communicate changes in state to each other. Either this is done with side-effects on variables inside an individual closure for that instance, which incurs the cost of redeclaring all methods upon construction; or else the state is communicated by calling an externally-visible method on the object, in which case it is impossible to guarantee the method has not been redefined. There are tricks for attempting to guarantee the integrity of an object, and there are still other tricks to surreptitiously break its integrity.

    Ultimately, you have to either trust access conventions, enforce them with a capabilities-model preprocessor, or just use lexical closures which are the only real data hiding in the language. =)

  • http://kevin-le.appspot.com Kevin Le

    Erik,

    I have the following observations:

    - Friends feature in C++ is almost useless. One can write solid OO C++ without ever having to use friends. But this is not important if you can and already make it happen for free with your technique.

    - What’s more important is: do I need to have boiler plate for each object, i.e.
    var A;
    (function() {
    var KEY = {};
    A = …;

    })();

    var B;
    (function() {
    var KEY = {};
    B = …;

    })();

    Is there a way improve so that you would need the boiler plate code only once?

    - Have you thought about turning this into protected, and use it in JavaScript inheritance? I think this could be useful (at least for me) if there’s not too much boiler plate code that gets in the way.

  • Pingback: Private in JavaScript | www@www

  • http://erik.eae.net Erik Arvidsson

    henrah: You are correct. Like you said, anyone can override _getPrivateWithKey to get access to the private key. Doh!

  • Pingback: Trying to be private in JavaScript | Eroarea 403

  • http://alttag.org Alan Pearce

    The technique below creates the guessPassword method on the Cartman objects prototype and keeps the “secret” variable private while only creating it once.

    function Cartman(){
    //This is called only for the first instance
    var secret = ‘Tea party’;
    Cartman=function(){
    //This becomes the new constructor
    }
    Cartman.prototype.guessSecret = function(guess) {
    return guess == secret;
    };
    return new Cartman();
    }

  • Pingback: Trying to be private in JavaScript | Slightly Nervous

  • http://erik.eae.net Erik Arvidsson

    Alan: Interesting. That solution makes the secret shared between all instances which you probable do not want.

  • Pingback: Chasing super

  • Duarte Cunha Leão

    When I found your article I thought: “I’m gonna give up, someone has already tried it and failed!” The pattern you present I also got to it, and also found it was flawed…
    But I am so stubborn…And continued trying new variants of the pattern.
    I finally found a way to achieve private instance state (and with normal prototype methods). Check it out: http://www.codeproject.com/KB/ajax/SafeFactoryPattern.aspx

  • http://with-love-from-siberia.blogspot.com/ ildar

    JavaScript is special programming language with own features. I don’t see urgent reasons to embed features from other languages. But if you really want or you need implement privates to your classes, you need strongly think — do you really this feature. Suggested examples with inner functions are weird and ugly because you create the public method to access to privates. Just you cover real privates with public method. I don’t have objection if you really need this. I can suggest the simpler code:

    // Example 1
    function A()
    {
    var privates = {};
    this.getPrivates = function()
    {
    return privates;
    };
    };

    A.prototype.setX = function(x)
    {
    return this.getPrivates().x = x;
    };

    A.prototype.getX = function()
    {
    return this.getPrivates().x;
    };

    // Example 2
    function A()
    {
    this.getPrivates = function()
    {
    return arguments.callee.privates = arguments.callee.privates || {};
    };
    };

    A.prototype.setX = function(x)
    {
    return this.getPrivates().x = x;
    };

    A.prototype.getX = function()
    {
    return this.getPrivates().x;
    };

    Of course, we declare an inner method in the both examples but this code is simpler and laconic.

  • Pingback: What the Heck is Shadow DOM? « Dimitri Glazkov

  • http://www.hcgdamlaturk.com hcg damla

    Alan: Interesting. That solution makes the secret shared between all instances which you probable do not want.

  • Duarte Cunha Leão

    Ildar: How can x in: “a.getPrivates().x = 2″ be considered private state?