Private Variables

Topics: Language Specification
Oct 2, 2012 at 8:40 AM

The following TypeScript allows the variable to be treated as private in TypeScript but doesn't result in a scoped variable in JavaScript:

class MyClass {
	private example: string;
    constructor() { 
		this.example = "Test";
	}
}

Results in:

var MyClass = (function () {
    function MyClass() {
        this.example = "Test";
    }
    return MyClass;
})();

It would be great if private really meant private - for example, but resulting in the following JavaScript:

var MyClass = (function () {
    var example;
    function MyClass() {
        example = "Test";
    }
    return MyClass;
})();
This means that in plain JavaScript, example is still private as it is scoped.

Developer
Oct 2, 2012 at 12:49 PM

The problem with using constructor function local variables for private storage is that they can't be accessed from functions on the prototype object (which is what methods on a class become in the generated JavaScript). Instead you need to create local function objects and that consumes a lot more memory. It would look something like this:

class StringBox {
    getValue: () => string;
    constructor (value: string) {
        this.getValue = () => value;
    }
}

As you can see, you need to create one function object per instance instead of a single function object shared by all instances through the prototype.

Anders

Marked as answer by Sohnee on 4/1/2014 at 1:18 PM
Oct 3, 2012 at 9:17 AM

Hi Anders,

That is a compelling reason to leave it as it is.

This is really just an education issue for people writing libraries with TypeScript that are being consumed from vanilla JavaScript.

Thanks

Steve

Oct 3, 2012 at 1:30 PM
Edited Oct 3, 2012 at 1:31 PM

It makes sense to use the underscore convention for "private" variables.  So that this:

 

 

class MyClass {
  private foo: string;

  constructor() {
    this.foo = "bar";
  }
}

 

Will result in this JavaScript:

 

 

var MyClass = (function() {
  function MyClass() {
    this._foo = "bar";
  }

  return MyClass;
})();

 

JavaScript developers are familiar with this convention and are aware that an underscore property/function is use-at-your-own-peril.

Oct 3, 2012 at 5:43 PM

Agree. Private members should be at least somehow distinguished from public members.

Oct 20, 2012 at 7:50 PM
Edited Oct 20, 2012 at 8:36 PM

I wanted to give my two cents on this. With regards to the criticism above... that is talking about accessing inherited private members (which is a protected scope, not a private scope).

If we are talking solely about a private scope and the point of TypeScript is to make javascript suitable for "application scale projects" I don't see why you would dismiss or minimize the importance of private scope at runtime. It can save a lot of grief when working with other peoples code!

Consider a scenario where you write a redistributable framework in TypeScript but consumers write javascript code against the compiled library. To me that feels like the most likely TypeScript usage scenario, where a few core maintainers work with TypeScript and the consumers largely do not.

Furthermore, why use a coding convention when it is technically possible to simulate private scope in javascript, by taking advantage of javascript's closure scope. 

function SomeConstructor() {
     var _private = "private";

     this.getPrivate = function () {
          return _private;
     }
}

TypeScript simulates all kinds of other abstractions that aren't explicitly part of javascript (like class based inheritance), why not simulate runtime private scope as well? All the technical means to do it are part of ES standards.

Oct 22, 2012 at 6:47 AM
Edited Oct 22, 2012 at 6:52 AM

I'd better give my "plus one" to the topic starter. I'm not quite sure I understand why everybody try to declare private variables inside the constructor?! We have a perfect closure as a class body provided by compiler. I don't see no probrem at all to have all our privates compiled just like this:

 

var MyClass = (function () {
    var example;
    function MyClass() {
        example = "Test";
    }
    return MyClass;
})();

In this case they are perfectly accessable from any prototype function defined in the scope of the closure (and this is exectly how the js code generated, btw). No need of any unnecessery "internal" getters-setters-helper-functions to reach them (as it was mention in some similiar thread here).

The only purpose of the way it's implemented now is variables with sort of protected access in case of inheritance.

Correct me if I miss the point somewhere.

 


Oct 23, 2012 at 11:53 AM
var MyClass = (function () {
    var example;
    function MyClass(value) {
        example = value;
    }
    MyClass.prototype.getExample = function() {
        return example
    }
    return MyClass;
})();

var test1 = new MyClass("test1");
var test2 = new MyClass("test2");

console.log(test1.getExample()) //test2
console.log(test2.getExample()) //test2

Here is the problem with what you described hyperartist

Oct 23, 2012 at 2:42 PM

JavaScript doesn't support private variables, full stop. Any attempt to hack it on, such as putting everything in the constructor (horrible idea) will just result in degraded performance.

The rather obvious solution, one that practically every JavaScript developer already does, is to make "private" variables begin with an underscore, thus telling anyone using the code "use at your own risk".

Oct 24, 2012 at 10:07 PM
Edited Oct 24, 2012 at 10:19 PM
mateo2 wrote:

JavaScript doesn't support private variables, full stop. 

 

Douglas Crockford thinks it does.

http://www.crockford.com/javascript/private.html

 

mateo2 wrote:

Any attempt to hack it on, such as putting everything in the constructor (horrible idea) will just result in degraded performance.

 

RE: "Hacks"

So it's OK to "hack in" class based inheritance patterns using javascript prototypes, but it is not OK to "hack in" private variables using javascript's closure scope. I guess I don't see consistency in this thought process.

 

RE: "Performance Concerns"

The inheritance abstraction chosen in TypeScript has some trivial memory overhead affiliated with it as well as does any abstraction. This doesn't mean abstractions are a "horrible idea", sometimes they are a reasonable trade off. The goal of TypeScript is to introduce maintainability and productivity and I'd argue private scope (at both compile time and runtime) is a part of that vision.

Oct 25, 2012 at 1:23 PM

 

Eric, constructors have "private" variables like every other closure. But JavaScript OBJECTS do not, ever.  For example, a "private" variable declared in the constructor is not available to any members of the prototype. Example:

 

function SomeConstructor() {
  var imPrivate = "ha!";
}

SomeConstructor.prototype.getImPrivate = function() {
  return this.imPrivate;
};

The latter will always return undefined. imPrivate is only available within the constructor.

Adding class inheritance isn't a hack. The Constructor/Prototype combination is a very close parallel to how classes work in other languages. There is no downside to doing it.

Hacking in private variables, which JavaScript does not support, has an obvious downside: your code will run slow. There seems to be very little (if any) upside compared to just adding a leading underscore.

 

Oct 25, 2012 at 3:25 PM

Currently, TypeScript doesn't have private properties, either (only intent, 8.2.1):

class MyClass {
	private secret: string;
	constructor () {
		this.secret = Math.random();
	}
}
var obj = new MyClass();
alert(obj["secret"]);

As Anders already points out, access to instance-private data seems to require methods-per-instance. That doesn't mean copies of function bodies, though: implementations are free to store closures (function pointers+private env). It is a trade-off, not an impossibility, and there are alternatives.

hypeartist shows a class-private property, which could be used as a secret map, to store per-instance data behind per-instance, public keys. That would protect the instance-private data from the outside, though other class instances could accidentally gain access. It would not require methods-per-instance.

Here is another approach (untested:-):

var MyClass = (function () {

    function MyClass(id) {
       this.id = id;
       var private_this = Object.create(this);  // this and more
       private_this.secret = Math.random().toString();
       this.guess = guess.bind(private_this);
    }

    function guess(guess) {
      var check = guess===this.secret
                ? "I'm not telling!"
                : "That guess is wrong!";
      console.log("("+this.id+"'s secret is: "+this.secret+")");
      console.log(this.id+' says: '+check);
    }

    return MyClass;
})();

var myObj1 = new MyClass("instance1");
var myObj2 = new MyClass("instance2");

console.log(myObj1,myObj2);

var guess = Math.random().toString();
console.log("guessing: "+guess);
myObj1.guess(guess);
myObj2.guess(guess);
Depending on how method binding is implemented, this requires only method-pointers-per-instance, giving private methods access to an extended this.

Dec 29, 2012 at 5:42 AM
Edited Dec 29, 2012 at 5:43 AM

There's a couple of ways you can get the desired private member variables and still maintain the current style of placing all method declarations on the prototype. The first possibility is to simply place the private member declaration outside of the constructor function, and at the same scope level that the prototype function declarations are at. The other option is to move the prototype function declarations inside of the constructor definition. This would definitely give the prototype methods access to the private members for the Greeter constructor without causing a single shared instance of the private member. I've included some examples below:

var Greeter = (function () {
    var greeting = message;
    function Greeter(message) {
        
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + greeting;
    };
    return Greeter;
})();
var greeter = new Greeter("world");
var button = document.createElement('button');
button.innerText = "Say Hello";
button.onclick = function () {
    alert(greeter.greet());
};
document.body.appendChild(button);
 
var Greeter = (function () {
    
    function Greeter(message) {
        var greeting = message;
        Greeter.prototype.greet = function () {
            return "Hello, " + greeting;
        };
    }
    
    return Greeter;
})();
var greeter = new Greeter("world");
var button = document.createElement('button');
button.innerText = "Say Hello";
button.onclick = function () {
    alert(greeter.greet());
};
document.body.appendChild(button);


Dec 30, 2012 at 12:57 PM

@dharric, as pointed out by @fdcamderron the first example will fail because the "greeting" variable is shared across instances:

 

var Greeter = (function () {
    var greeting;
    function Greeter(message) {
        greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + greeting;
    };
    return Greeter;
})();
var greeter = new Greeter("world");
var greeter2 = new Greeter("armageddon");

var button = document.createElement('button');
button.innerText = "Say Hello";
button.onclick = function () {
    alert(greeter.greet()); // Hello, armageddon
};
document.body.appendChild(button);

The second example will also fail for the same reason. In addition it is more inefficient because the "greet" function is redefined every time the constructor runs.

 

Noel

Jan 3, 2013 at 10:22 PM

After having played (ie rewritten a project that was in JavaScript) with TypeScript for a good portion of the holidays, I would agree with the convention of prefixing an underscore on private variables.  It follows what every other JavaScript library does 90% of the time to handle private variables.

Now TypeScript does have it's own conventions that already prefix items with _, like the this scope in lamba functions, as an example, so it may make sense to prefix private variables with two underscores, or perhaps modify the existing convention, if there is any chance of a collision.

Jan 5, 2013 at 10:24 AM

TypeScript doesn't prevent you from adopting underscore prefix, neither does it prevent any other naming convention.

 

It would be bad for TypeScript to enforce a convention though.

Jan 8, 2013 at 6:47 PM
mihailik wrote:

TypeScript doesn't prevent you from adopting underscore prefix, neither does it prevent any other naming convention.

 

It would be bad for TypeScript to enforce a convention though.

I agree on this. As a C# developer I'm used to the convention of prefixing private members with an underscore. I follow that convention when I'm doing TypeScript and Javascript development too.

As you can mix TypeScript and Javascript it would be very annoying if the TypeScript compiler would alter private member names of the TypeScript specific parts of a script while the Javascript specific parts of the script stayed unaltered. That would result in broken conventions in the compiled Javascript, and that would suck.

C#/Javascript doesn't enforce me to follow any convention and TypeScript shouldn't either.

Jan 9, 2013 at 1:41 AM

The typescript "private" seems leading in too much problems in my point of view, mainly because it's allowing on the subclass to override properties and method without any error.

Why not just give up the private and completely replace it by "protected", i think that at least it will allow us to receive proper warning/error.

Jan 24, 2013 at 8:40 AM
Edited Jan 24, 2013 at 9:00 AM

Why can not we make a PRIVATE METHOD to a closure?

 

example:

Typescript:

class Greeter {
    greeting: string;
    private hello(){
        return this.greeting;
    }
    public hi(){
        alert(this.hello());
    }
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

JavaScript:

var Greeter = (function () {
    var hello = function(){
       return this.greeting;
    }
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.hi = function () {
        alert(hello.call(this));
    };
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();

 

 

p.s. Another implementation of private members:

var Greeter = (function () {
    var privates = {};

    var setPrivate = function(key, value){
          privates[this.__id][key] = value;
    };

    var getPrivate = function(key){
         return privates[this.__id][key];
    }
    function Greeter(message) {
        this.__id = generateUniqId();
        private[this.__id] = {};
        setPrivate.call(this, 'greeting', message);
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + getPrivate.call(this, 'greeting');
    };
    return Greeter;
})();
Mar 12, 2013 at 5:53 AM
Edited Mar 12, 2013 at 6:01 AM
Private fields are a hack in any language, not just in JavaScript. It worries me to see this many people suggesting
implementing private members through closures, and incorrectly at that.

Since member visibility is not possible to implement on a hardware level, it can only be emulated or simulated in
software - most compilers do this using a combination of name mangling and compile-time visibility information.
For example, in GCC's C++ compiler, all functions, classes and other constructs are treated as distinct objects, with
each class being given their own vtable, containing references to functions for that class - this would be loosely
analogous to JavaScript's prototype object. Furthermore, each distinct object, once instantiated inside the compiler's
list, is name mangled according to certain rules, resulting in unique names for each class and function, based on
namespace and parameter information. Each class instance gets a pointer to its vtable, ensuring the correct
function is called at runtime, regardless of apparent name conflicts (i.e. private methods declared with the same
name in a parent and child class). If you were to make direct calls to these name-mangled functions, you'd be able
to access them just fine, as the compiler (at that point) won't be checking for accessess of variables it believes are
outside the visibility of the programmer, instead preferring to do scope and access level checks on a higher
semantic level.
_(note: I'm writing this, having woken up about 20 minutes earlier - coffee hasn't settled in yet. Any mistakes and/or
generalizations or over-simplifications can be attributed to that, and to trying to make a point understandable by
people other than compiler specialists)._

So why am I telling you this?
Quite simply, because I'm wondering why TypeScript doesn't already do what most other compilers do - name
mangle private fields. Since private fields really should be private to the class being compiled, we can safely assume
all references to that private field happen inside the file being processed. Hence, we can safely generate a mangled
name, doing a serach-and-replace for all accesses to that private member.

What would need to happen, though, would be to come up with some sane name mangling scheme. For example,
a simple solution would be to concatenate module[] + class name and MD5 hash the value, then call the resulting
field
_p_hash_fieldname
This shouldn't be too difficult to implement in a future release. People depending on access to private fields outside
a class are (or, at the very least, should be) depending on undefined behaviour anyway, so the fallout of such a
change should be minimal, but the potential gains in program reliability would be enormous.


My two cents.
-cb


edit: why are my lines split arbitrarily in the actual post, but correctly in preview?
edit2: manually inserted line breaks
Mar 12, 2013 at 5:54 AM
Edited Mar 12, 2013 at 5:54 AM
Accidentally hit reload and got my post posted twice...
Coordinator
Mar 12, 2013 at 9:42 PM
@codebeard - There was an ECMAScript 6 recommendation at one point for private names, which is effectively what you're suggesting. It would be names that you couldn't "guess", but would rather have to have a handle to them. This would be pretty straightforward to adopt once ES6 adopted it.
Mar 12, 2013 at 10:14 PM
Edited Mar 12, 2013 at 10:17 PM
Except for the fact that what I'm suggesting would be implementable now, and completely backwards-compatible
down to the first versions of JavaScript.
Not to mention the fact that ES6 support would need to appear in browsers until that feature could be reliably
used, no?
Jun 9, 2013 at 8:59 AM
In javascript is often used the revealing prototype pattern. I think with this pattern could be mimic a private function, although private fields cannot be declared on prototype and shared across all instances. Will typescript support private functions?
    var Greeter = (function () {
        function Greeter(element) {
        }

        Greeter.prototype = function () {

            var start = function () {
            };

            var stop = function () {
            };

            var privatefunc = function () {
            }

            return {
                start: start,
                stop: stop
            }
        }();

        return Greeter;
    })();
Jun 9, 2013 at 1:04 PM
@pbacka,

In your sample it's not possible to access privatefunc from the Greeter constructor. In order to do that we need to move privatefunc to the outer closure:
  var Greeter = (function () {
        function Greeter(element) {
            privatefunc.call(this);
        }
        var privatefunc = function () {
        }
        Greeter.prototype = function () {
            var start = function () {
            };
            var stop = function () {
            };
            return {
                start: start,
                stop: stop
            }
        }();
        return Greeter;
    })();
Now once we've done that this suggestion is essentially the same as mantsevich's above (the first one - I think the second suggestion is faulty).

I don't see why TS shouldn't implemented private methods as functions within the closure.

The only complication is that the "this" context needs to be set explicitly for the private functions. But that shouldn't be too difficult for the compiler.

NB: There are at least two separate discussions on this thread: the original one was about private fields, which is not possible to do; this one is about private methods.
Jun 9, 2013 at 7:05 PM

I for one prefer the design time enforcement of private values rather than run time. It keeps object size down, makes `this` easier to deal with, and produces more readable JavaScript.

A community standard in JavaScript to mark fields that should be private is to prepend the name with _, which is what I usually do with private members in TypeScript. This makes it obvious to JavaScript devs using your code what the intention of a certain method or field is. IIRC, Dart uses _ as the only method to mark private members.

Jun 9, 2013 at 8:01 PM
I agree with AndrewGaspar and do exactly the same thing. Private should be enforced at build time only, not run-time. I don't need that extra baggage in my JS code and I too use the _ prefix to let JS devs understand the scope at a glance.
Jun 10, 2013 at 3:03 PM
@AndrewGaspar/@PhotonStorm, it's not clear whether you are responding to my post or not. There is no extra baggage from implementing private methods. It would work as follows:

The code
class Foo{
    constructor(){
        this.getFoo();
    }
    private getFoo(){
    }
}
should compile into:
var Foo = (function () {
    function Foo() {
        getFoo.call(this);
    }
    function getFoo(){
    }
    return Foo;
})();
At present the private method getFoo compiles into a method on the prototype:
    Foo.prototype.getFoo = function () {
    };
There are at least two problems with this.
  • Permits junior developers from writing code like
var foo = new Foo();
var bar = foo["getFoo"](); // Access private method, yay!
  • Prevents JavaScript minifiers from doing their job. Because getFoo is on the prototype a minifier will assume it is a public method (without further annotation) and leave it alone. In fact there is no harm in turning 'getFoo' into say 'x' because it is visible only within the closure.
With regard to the question of private fields (e.g. foo.bar = 10), none of the suggestions on this thread would work. It just cannot be done.

One may as well prefix them with an underscore if that makes them feel happier. But I wouldn't get TypeScript to do that on your behalf, because that is a code convention - not a language construct.
Jun 10, 2013 at 10:42 PM
I completely agree that TypeScript shouldn't enforce the addition of an underscore to conform to the code convention. That was just my suggestion to OP on how to best solve his problem rather than enforcing run-time private methods.

I can see the benefits of just declaring the function inside of the class declaration closure, though. Hm... not sure how I feel about that. It seems reasonable.

Andrew Gaspar


Jun 10, 2013 at 11:19 PM
I wonder what difference it would make in terms of speed and garbage collection, especially with an intensively used class. At least traditionally closures have been more expensive (to create and write to) but with modern compiler advances that may no longer be the case.
Jun 11, 2013 at 12:18 AM
Well, I mean, closures are already used in class creation regardless of whether or not this change to private methods is made.

My biggest problem with this change I suppose would be that it creates an inconsistent behavior between private members and private methods. Private members can be accessed at run time outside of the class because they have to be attached to the object instance in order to be accessed by methods and by methods in the super class, but private methods would not be. This might be fine, but there would be that difference.

Andrew Gaspar


Nov 17, 2013 at 6:53 PM
Edited Nov 18, 2013 at 9:46 AM
nabog wrote:
There is no extra baggage from implementing private methods. It would work as follows:
    var Foo = (function () {
        function Foo() {
            getFoo.call(this);
        }
        function getFoo(){
        }
        return Foo;
    })();
How would you access private/public members from within your proposed private methods? It seems like this approach would work only for static methods. The same would also work for static members.

You could pass in the values you need when you call the private methods, but then you would need to know which variables the method needed. If any changes were made to those variables from within the private method, it would be difficult/costly to persist them back to the original instance object.
Nov 18, 2013 at 6:50 AM
Well we are setting the "this" context for the private method so it's safe to access private/public members:
var Foo = (function () {
    function Foo() {
        this.bar = "bar";
        getFoo.call(this);
    }
    
    function getFoo(){

        console.log(this.bar); // Bar
    }
    
    return Foo;
})();
Nov 18, 2013 at 8:43 AM
Edited Nov 18, 2013 at 9:48 AM
nabog wrote:
Well we are setting the "this" context for the private method so it's safe to access private/public members:
var Foo = (function () {
    function Foo() {
        this.bar = "bar";
        getFoo.call(this);
    }
    
    function getFoo(){

        console.log(this.bar); // Bar
    }
    
    return Foo;
})();
Wow, sorry! I completely read over that.

Anyway, the problem I foresee with this approach is that we don't always know how a method will be called until run-time. As such, the TypeScript compiler would have to be really really smart to know when to insert .call() / .apply() / .bind().

Consider the following TypeScript code:
class NicknameGenerator {
    private name: string;
    
    public generateNickname(name: string, type: string) {
        function getDefaultName() {
            return "Rebel";
        }
        
        var baseName = name + " the ";
        var methodName = "get" + type.charAt(0).toUpperCase() + type.slice(1) + "Name";
        var getNickname = this[methodName];
        
        if (!getNickname || typeof(getNickname) !== "function") {
            getNickname = getDefaultName;
        }
        
        var nickname = baseName + getNickname();
        
        return nickname;
    }
    
    private getCoolName() {
        return "Dude";
    }
    
    private getFratName() {
        return "Bro";
    }
}

var nicknameGenerator = new NicknameGenerator();

console.log(nicknameGenerator.generateNickname("John", "cool"));
How would the TypeScript compiler know what to do with the call: getNickname()? It would have to understand that the value of getNickname varies and sometimes refers to a private member function and sometimes refers to an inner function. It would then have to use that understanding to compile the code into something like:
if (!getNickname || typeof(getNickname) !== "function") {
    getNickname = getDefaultName;
} else {
    getNickname = getNickname.bind(this);
}
I don't think a compiler will ever be that smart... not yet at least :)

Yes, this is a fabricated example, but I think it's reasonable to assume that if TypeScript worked as you suggest, there would be some limitations.
Nov 18, 2013 at 10:17 AM
Edited Nov 18, 2013 at 10:41 AM
Yes, if the name of the private method were to be generated dynamically then that would cause problems.

It would also cause problems even if the private methods went on the prototype, because in some future versions the private names may be mangled (e.g. for minification purposes).
Nov 21, 2013 at 4:28 PM
Why not represent each private member as a function prefix with the current class name? Something like this:
A = (function() {
  function A()  {
    this._A$privateMember = null;
  }

  A.prototype.someMethod() {
    return this._A$privateMember;
  }

  return A;
})();
It's uggly, I know, but it works and don't give errors at runtime. If necessary, the prefixed class name could be something like the FullTypeName.
Coordinator
Nov 22, 2013 at 3:27 PM
Mangling the names of privates is sort of a split-the-baby solution. Most of the people wanting "real" private variables want closure (i.e. really actually private) privacy and wouldn't be satisfied with properties that still show up on the object, and conversely, most of the people who are satisfied with compile-time enforcement enjoy the ease of debugging that having unmangled property names brings.
Dec 1, 2013 at 1:36 AM
RyanCavanaugh wrote:
Mangling the names of privates is sort of a split-the-baby solution. Most of the people wanting "real" private variables want closure (i.e. really actually private) privacy and wouldn't be satisfied with properties that still show up on the object, and conversely, most of the people who are satisfied with compile-time enforcement enjoy the ease of debugging that having unmangled property names brings.
Agree.

Also, private members in JavaScript by convention are typically just pseudo-private, e.g. prefixed with an underscore. If somebody willingly violates the privacy of these members, they do so knowingly, and it is their own responsibility and their problem if for example the name or type of that private member changes in the future.

Ironically, most languages that do offer private variables also offer some means of circumventing that privacy (typically by reflection) so one might wonder, what is the point really, or is it really worth the effort?

If or when JavaScript itself offers private variables at some time in the future, TypeScript should map it's private variables using that feature - until then, in my opinion, it should stick to what JavaScript and the JavaScript community at large have agreed on.

Psuedo-private is "sufficiently private" - privacy in many other languages is mostly advisory anyhow, and sometimes has to be violated for various valid reasons...
Dec 2, 2013 at 3:47 AM
Here's an approach to runtime-enforced private properties that doesn't redefine the function objects per instance and works back through Ecmascript 3. The technique is from a project I've been working at on the side for the past few months with some goals in common with TypeScript, before I came across TypeScript a few days ago.

The above discussion has pretty well shown you can't do this using any single quick trick like closures. Consequently there is a bit more code to work through with this solution.

Here's a severely stripped-down version of the concept, written just for this post and optimized for clarity and emphasis on the central parts of the technique. It glosses over things like support for private static members, support for dynamic classes, and ES3 alternatives for some ES5 functions for the sake of brevity. I can show extended code to handle those if there is interest in the overall technique.

You can also load it up & run it at http://jsfiddle.net/Bz3An/
/** D E M O  A P P L I C A T I O N  C O D E **/
// Making use of the conceptual code below
var publicProps = {"contents": "quick brown foxes"};
var privateProps = {"container": "little boxes"};

var publicMethods = {
    "toString": function(){
        return this.container + " of " + this.contents;
    },
    "setContainer": function(requestedContainer){
        if(this.isAllowableContainer(requestedContainer)){
            this.container = requestedContainer;
        } else {
            throw new Error(requestedContainer + " is not an acceptable container for " + this.contents);
        }
    }
};

var privateMethods = {
    "isAllowableContainer": function(container){
        return this.contents.substr(-2) == container.substr(-2);
    }
}

// define a new class
var Packer = classGenerator(publicProps, publicMethods, privateProps, privateMethods);

// create an instance of our class
var worker1 = new Packer();
// and see what we've got...
console.log(worker1.toString());

var worker2 = new Packer();
// another instance, let's modify the default state
worker2.setContainer("big enclosures");

// confirm worker2 state modified, worker1 state unaffected
console.log(worker2.toString());
console.log(worker1.toString());

// what was the container for worker 2, again?
console.log("reading worker2's (private) container property externally: " + worker2.container);
// Oops! Can't read that private property. Public properties are where you'd expect, though
console.log("reading worker2's contents property externally: " + worker2.contents);

// properties apparent on an instance are only the public members, so privates
// aren't exposed with things like Object.keys or for..in
console.log("The properties of worker1 are: " + Object.keys(worker1).join(", ") + ".");

// Public methods which call private methods also work as expected.
try{
    worker1.setContainer("open fields");
    throw new Error("Shouldn't see this output -- isAllowableContainer throws first");
} catch (e){
    console.log(e.toString());
}

/** C O N C E P T U A L  C O D E **/
function classGenerator(publicProps, publicMethods, privateProps, privateMethods){
    // A unique function object is set as the locatable constructor of each instance
    // to provide a good place to retain references to private members
    function constructorPrototypeInitialization(){
        c.prototype = Object.create(publicMethods);
        c.prototype.constructor = function _class(){
            c.apply(this, arguments);
        }
    }
    
    function wrapMethod(method){
        return function(){
            var priv_context = this.constructor.__privates;
            var changeTracker = Object.create(priv_context);
            
            var retVal = method.apply(changeTracker, arguments);

            // move writes to the correct location
            var writes = Object.keys(changeTracker);
            for(var i = 0; i < writes.length; i++){
                var write = writes[i];
                if(write in privateProps){
                    priv_context[write] = changeTracker[write];
                } else {
                    this[write] = changeTracker[write];
                }
            }
            
            return retVal;                              
        }; 
    }
    
    // wrap the app-provided methods so they are called in private context
    for(var method in publicMethods){
        publicMethods[method] = wrapMethod(publicMethods[method]);
    }
    for(var method in privateMethods){
        privateMethods[method] = wrapMethod(privateMethods[method]);
    }
    
    var c = function _class(){
        cloneInto(this, publicProps); // initialize public properties
        var p;
        _class.prototype.constructor.__privates = p = Object.create(this);
        refInto(p, privateMethods); // add references to the private methods
        cloneInto(p, privateProps); // initialize private properties        
        
        // this inherits from the current value of _class.prototype, but reinitialize
        // for next instance
        constructorPrototypeInitialization();        
    }
    
    // prep for the first instance
    constructorPrototypeInitialization();
    
    return c;
}

function cloneInto(intoThis, fromThis)
{
    var keys = Object.getOwnPropertyNames(fromThis);
    for(var i = 0; i < keys.length; i++){
        intoThis[keys[i]] = clone(fromThis[keys[i]]);
    }
};

function clone(jango){
    var boba;
    if(jango == undefined){
        boba = jango; // null == undefined, so this does both
    } else if(Array.isArray(jango)){
        boba = [];
        for(var i = 0; i < jango.length; i++){
            boba[i] = clone(jango[i]);
        }
    } else if(typeof(jango) == "object"){
        boba = {};
        cloneInto(boba, jango);
    } else {
        boba = jango;
    }
    return boba;
};

function refInto(intoThis, fromThis){
    "use strict";
    for(var member in fromThis){
        intoThis[member] = fromThis[member];
    }
};
What's going on here?
The basic idea is to represent instance state in a two level object inheritance chain that is assembled when an instance of your class is newed up. The base object in the chain is 'this', and public properties are initialized on it in the constructor just like TypeScript compiled code currently does for public and private properties. But here, for private properties the constructor creates a second object inheriting from this and initializes the private properties there. Then you add wrappers around the class methods to call them in the context of the object containing the privates (and inheriting the publics), and voila, runtime-enforced private properties.

Some things about this technique that I think are really awesome:
  • TypeScript currently litters 'private' members onto its instance-level objects. As a result, potentially practical code performing a for..in over the properties of an instance not only finds out about all the private members, but also has no way of even distinguishing which are supposed to be public (other than knowledge of some naming convention the class author used to denote privates, which isn't typically one of the things you should need to know about a class interface.) With this technique, privates are really private, and don't show up in such inspections of the instance's properties.
  • The application provides the class methods as part of the class definition process (which would be compiled away if used in TypeScript), and those method objects are only instantiated once. Within class methods, application developers have full access to public and private members through this.
  • The technique extends to the concept of enforced protected members as well (with an additional level of inheritance), something I didn't do above so I could respond to the topic at hand as directly as possible, but something which I definitely think is worth doing.
There are some ugly realities to Ecmascript that require some extra jiggering, in particular re: writing to properties (without lines 77-85, writes to public properties would end up as overrides on the privates object, but never appear externally), and re: the need for the wrapper functions to reference the privates object of any instance directly, without just sticking it on the instance (unexpected clutter to app developers) and without keeping those references around elsewhere somewhere where they'll later cause memleaks. My best idea so far for this is the separate constructor function per instance, which the privates object is then attached to.

Some pre-emptive defense of things that are likely to be criticized:
Dec 4, 2013 at 3:07 AM
So I'm looking around a bit more at the state of TypeScript and MS's roadmap, and it basically says breaking changes in the compiler are going to stop very soon. Does this mean it is too late for any scheme that makes "private" members private or distinguishable in some way?

There is a long discussion on this thread suggesting there's just no way to do privates, and the TypeScript langauge spec (section 8.2.2) comes right out and says such a thing can't be done. I don't know if I think the exact technique I illustrated above should be adopted by TypeScript, but I believe it is good enough to show that it can be done. If member accessibility in TypeScript has been designed based on a belief that it cannot, I think that design deserves one more look before this characteristic of TypeScript is set in stone forever. If it can be done, shouldn't it be?

I'd also argue that TypeScript seems poised to evolve much faster than ECMAScript has, and giving privates a bit more teeth now frees up a lot more options for future evolution. If privates are in fact just properties of instantiated classes, that will be the only way TypeScript will ever be able to implement privates in order to preserve compatibility. On the other hand, if privates are not apparent on objects in the ECMAScript manifestation of the code, it would be much safer to assume only other TypeScript-compiled code touches privates, freeing the underlying technique to change completely in later compilers -- perhaps even to map to native privates, if such a thing exists someday.
Coordinator
Dec 5, 2013 at 8:37 PM
When we say "possible", we mean "possible under our design constraints":
  • The emitted JS is idiomatic
  • Boilerplate is minimal
  • No additional overhead compared to normal JS OOP
This approach is really interesting, but doesn't meet those constraints. Allocating an extra object per function invocation is going to be unacceptable overhead for most people, and a 'private' approach that can still be circumvented through normal means doesn't meet the bar of closure privacy. It's a trade-off that meets neither major goal.
Dec 7, 2013 at 9:28 PM
Well, my code above doesn't have the benefit of going through a compilation step, and so must be able to execute methods whose bodies are exactly what was declared by the application. If you transform the emitted function bodies according to some rules a compiler could easily implement, you could dispense with the performance overhead at the cost of the emitted method body code being slightly different from the TypeScript method body code (ie, even when not using TypeScript features in your method implementation). A quick look back through this thread makes it look like that approach hasn't been shot down yet...would any such transformations be entertained?
Dec 30, 2013 at 6:06 AM
i've found this way to create Javascript private variables:

function MyClass(value) {
    var example = value;            // <--- This is Private
   
    this.getExample = function() {
        return example;
    }; 
}

var test1 = new MyClass("test1");
var test2 = new MyClass("test2");

alert(test1.getExample()); //test1
alert(test2.getExample()); //test2
Coordinator
Dec 30, 2013 at 5:40 PM
danfromisrael, this creates an extra closure per method per class instance, which was not a performance trade-off we were willing to take.
Dec 30, 2013 at 8:07 PM
Yes, not to mention you would end up with an instance-specific function property, instead of a prototype-based one. Performance wise, it's also not good to re-create function properties for every new object (along with closures, which are additional object instances as well).

Bottom line, for performance reasons, I agree that functions need to stay as prototypes, which unfortunately does mean prototype functions must access instance properties using "this". Without closures, like your example, it's not possible to create true private variables (can't have it both ways).

That said, I'm always a fan of hybrid solutions, and if a developer didn't care about performance, I think adding on a new keyword to allow private variables in the fashion you posted would be nice (the compiler could detect usage and move things around as needed I guess), but remember, you can already do what you posted in TypeScript. There's nothing stopping you from using your code above in TypeScript - it's not a new language. See example:
class MyClass {
    getExample:()=>any;
    constructor(value) {
    var example = value;            // <--- This is Private
    this.getExample = () => {
        return example;
    }; 
   }   
}
var mc = new MyClass(123);
var result = mc.getExample();
(see it in the playground: http://goo.gl/ewaw2S)
Dec 31, 2013 at 2:36 AM
Despite all these clever ideas, I still think the simplest answer is: it's not important.

Prefixing the variable name with an underscore is "private enough" - you've been warned the property is private, and if you decide to access it anyway, that's your problem, you do so knowingly. Just as, in other languages that have privacy and reflection, you bypass that privacy knowingly.

I think, compile-time privacy is the simplest and safest solution - it deviates minimally from normal JS practices and patterns, doesn't sacrifice performance, and doesn't require structural changes if eventually JavaScript gets support for actual private variables; at that time, the compiler would simply (probably optionally) flag the properties as private.

Why invent complicated/contrived solutions to problems that have simple solutions?
Dec 31, 2013 at 9:20 PM
mindplay, personally I lean to the "invent a complicated solution" side only as long as making things private is a feature of the language at all. Using a naming convention alone wouldn't bother me, but in TypeScript, to properly make something private involves the code containing redundant information everywhere: say private and put an underscore on the member name. Yes, many developers choose to code this way in other languages too, but TypeScript would be unique in that you'd be required to do both to prevent all unknowing access to things intended to be private (ie, if external JS interfaced with it). That seemed like poor enough language design to me to see if something couldn't be done about it.
Jan 1 at 4:07 PM
IMO any kind of overhead for the sake of truly private methods is unacceptable.

Having been through this discussion a few times, the solution I would now like to see is for TS to provide an option to minify the compiled JS.
This would naturally mangle private methods - the added benefit, for example:
class Foo {
    public getBar(){
        this.getFoo();
    }
    private getFoo(){}
}
Should compile into
var Foo = (function () {
    function Foo() {
    }
    Foo.prototype.getBar = function () {
        this.p1();
    };

    Foo.prototype.p1 = function () {
    };
    return Foo;
})();
This would stop people from treating private methods as just something one accesses with bracket notation: foo["getFoo"]()

Of course this does not provide any security if that is the primary concern. But if you do have state that needs to be protected from hackers (as opposed to novice developers) then that can be achieved via a closure.
Jan 2 at 12:17 PM
How about simply annotating private members with @private in the generated JavaScript?

That way, even consumers of the compiled JavaScript have been clearly informed, and the need to prefix methods with an underscore to indicate privacy also goes away...

Being able to fully protect state from hackers via closures is a debatable benefit - I can still replace the actual accessors on your prototype if I wanted, or substitute your entire constructor, etc... and in the rare case where that is actually required, you can still use closures in TypeScript. You can also return in a constructor as per JavaScript if you like, and keep anything you wish in the constructor's scope "private".
Jan 6 at 3:03 PM
The annotation idea is not bad, because that would enable minifiers such as Google's closure to get down to business on the generated JavaScript file.

My preference is for TypeScript perform the minification in-house. There is a work item out for this: https://typescript.codeplex.com/workitem/157

Regarding the security issue, yes, that is also my point: That needs to be implemented on a case-by-case basis and not something that TypeScript should worry about at all. That can be effected with closures in conjunction with Object.freeze or Object.seal to prevent tampering. These tend to be very special cases IMO.
Mar 31 at 8:48 AM
I just want to say, prepending public properties with "warning" prefixes, or obfuscating property names, is not encapsulation. It's noise, and makes APIs ugly. Way to uglify a new language, guys. I'd have taken the performance hit; as a user of the language the choice should have been mine.
Mar 31 at 12:46 PM
Edited Mar 31 at 12:50 PM
For other observers of this thread, here is the performance difference. The cost of object construction is 5x-6x slower than raw prototypes (in Chrome) but honestly it's comparing nanoseconds per instantiation. http://jsfiddle.net/gzqWe/7/ Actually, in IE11 the difference is about 1.5x on my machine.
Won't comment on memory consumption (which, yes I know, is hugely important) as I don't know how to tool for measuring that .. :)
Coordinator
Apr 1 at 8:06 PM
To make the comparison more apt to real-world code, you should have much more than one method per object.

Even having only 4 methods per object instead of 1, the results on my machine (in Chrome) were 1,626 vs 15,444 - nearly a tenfold difference. And that's still a small class.

On the memory side, we can just do math (to avoid getting confused by GC / JIT optimisations that are host-specific). Let's say we have 10 classes, each with 20 private methods, and we create 400 instances of each class. The 'non-private' version needs to allocate 10 * 20 = 200 closures. The 'private' version needs to allocate 20 * 400 = 8,000 closures. In addition to memory pressure, that's a also 20-fold difference in the number of things the GC needs to track and clean up. Having class instances be closures instead of simple data objects with prototype pointers also makes the GC's job quite a bit harder to begin with.
Marked as answer by Sohnee on 4/1/2014 at 1:17 PM
Apr 1 at 8:26 PM
What Ryan said.

Also, what's the point in trying to force a feature into the compiled code that the target language doesn't have?

Some day JavaScript will have visibility modifiers, and at that point we can use them - until that time, JavaScript members are all public, because that's the way the language works. Trying to emulate different semantics by mangling the generated code is going to do more harm than good, and besides, JavaScript programmers are used to the convention of _ meaning (at least) "enter at your own risk". You may not like that, but then your quarrel is with JavaScript (whose maintainers are working on the matter anyhow) and not with TypeScript.
Apr 1 at 8:35 PM
Further more, using the same line of thinking, you could argue that generated code should have type-checks - you could generate run-time type-checks everywhere, but does that add any value in a JavaScript world where type-checking isn't something JavaScript developers expect, or will it just get in the way? JavaScript developers do not expect visibility modifiers, because that's not a concept that exists in JavaScript land.

In order for the generated code to be as interoperable with the JavaScript eco system as possible, the generated code needs to not only be true and accurate to TypeScript - it needs to be true to JavaScript, meet JavaScript developers' expectations, and not pollute the eco system with concepts, elements or artifacts that do not belong in that world.

Just my personal philosophy.
Apr 1 at 10:01 PM
Edited Apr 1 at 10:10 PM
I am not against name mangling at all for private members. IMHO, this would be a deterrent to others wanting to use them. Instead of just "__myprop" the private result might be "__myprop123" (the first number perhaps starts with a value based on the current time, and simply increments by 1 globally for each one), or even perhaps something that CANNOT be accessed easily using ".", such as "__myprop@AXY" (though yes, indexing is still one way). This is not something far fetched from what is normal in the JS world. It's common to adorn private properties with $ or _ or __ or __xxx__ to prevent access, so I don't see the big deal. A minimizer changes names also, does it not? (for obfuscation, so...)
Apr 4 at 3:34 AM
Edited Apr 4 at 3:40 AM
I am not against name mangling at all for private members.
I believe you will find the TypeScript team is generally against any feature that requires altering the shape of the generated code from the shape of the original TypeScript code.
It's common to adorn private properties with $ or _ or __ or __xxx__ to prevent access
And nothing would prevent you from doing that in TypeScript either, e.g. private $getFoo() - same as in JavaScript, prefixing/postfixing variables can be done just the same, if you need to somehow communicate a stricter warning to API consumers - if you absolutely feel you must. Mangling the shape of the code isn't necessary for that. (I still don't recommend it though - whether it's you or the compiler mangling the names, it creates the same maintenance problems.)
A minimizer changes names also, does it not?
You can't compare that scenario - code that comes out of a minifier is decisively not intended for developer consumption, but for machine consumption. It's optimized for delivery, not for maintenance. Code that comes out of the TypeScript compiler is decisively intended for consumption by JavaScript developers and for ongoing maintenance.

For the same reasons, TypeScript does not give you an option to compile accessors in a way that requires mangling, e.g. synchronous getX() and setX() methods for a property X - your options are use them, or don't. Similarly, visibility modifiers, however they are implemented and supported, your options will most likely be use them, or don't - the difference here is that code can "degrade" for JavaScript interpreters that do not support visibility modifiers, without adversely affecting the program at run-time.

Essentially, the problem you're facing here, is strictly a design-time/development-time problem, as far as JavaScript interpreters without support for visibility modifiers are concerned - the feature does not exist and cannot be elegantly modeled in such as way that it will be enforced at run-time, and, because this is not a JavaScript language feature, it isn't expected by JavaScript consumers in the first place. We can't enforce type-hints at run-time either, and we shouldn't, for all the same reasons.

You're pursuing a solution to a problem that isn't there in the first place. When JavaScript has visibility modifiers, this will become a problem, and the solution will then be very simple and elegant. Until then, visibility modifiers is not something that exists in JavaScript, just like other (design-time/development-time) features in TypeScript that don't exist and aren't (and shouldn't be) modeled in the generated JavaScript code.

JavaScript is more than just a run-time environment to TypeScript - unlike e.g. Dart which has a very limited ability to interop with non-Dart native JavaScript code, in either direction. Name mangling is one reason for that. TypeScript has a much closer relationship with JavaScript than e.g. Dart and that's a big feature to give up to provide developer features for JavaScript consumers at run-time.
Apr 4 at 4:05 AM
Edited Apr 4 at 4:30 AM
And nothing would prevent you from doing that in TypeScript either
I never said I was prevented.
it creates the same maintenance problems
I have no idea how that would be a maintenance problem, since the compiler would generate the mangled name.
You can't compare that scenario - code that comes out of a minifier is decisively not intended for developer consumption, but for machine consumption.
True in part, but I gather many minimized scripts also contain the added bonus of obfuscating proprietary code (for some people). I would think mangled names would be inline with this idea.
as far as JavaScript interpreters without support for visibility modifiers are concerned - the feature does not exist
Well, apparently, JavaScript doesn't have type enforcement and generics either. The way I view TS is that is ADDS a layer of control and type help/protection desired for building large scale JS apps, so this statement doesn't hold much ground.
You're pursuing a solution to a problem that isn't there in the first place
Untrue - if there was no problem, there would not be a big discussion. Perhaps not for you, but it is for some it seems.
When JavaScript has visibility modifiers, this will become a problem, and the solution will then be very simple and elegant.
... and until then, there's no harm in doing something else.
Until then, visibility modifiers is not something that exists in JavaScript, just like other features in TypeScript that don't exist and aren't (and shouldn't be) modeled in the generated JavaScript code.
I respect your opinion, and equally disagree. ;) There are no inheritance keywords in JS either, but coding is required (and code for extending is inserted). There is no "(x:number, ...args)" in JS implicitly either, so a "for loop" needs to be inserted by TS to create a new array and offset it. Using lambda expressions inserts a "var _this=this" automatically (for closures), which has caused an issue report at one point (same goes for "_i" in auto generated for loops, in which there is another issue report). I'm sure there are many more examples. I see TS as transcoding to JS according to keywords and modifiers, and thus, I don't see it as being such a huge leap. For that matter, why not just minify private variables ahead of time - that's not far fetched.
Apr 4 at 4:29 AM
Just a side note, I have used various Google map related APIs many times, which are minified, and many private properties don't have any meaningful names. You must access them using functions, because there's no guarantee the names (like "$h", "Uc", "wb" [taken from an actual map related API object - FOR DEVELOPERS I might add]) will remain the same. At the same time, there are properties with "_" before the property names, which are mostly likely readonly, but which can also be accessed directly. I think minifying private properties like this is NOT a bad idea at all, and certainly not even a unique one.