About private names

Allen Wirfs-Brock allen at wirfs-brock.com
Sun Mar 20 09:30:44 PDT 2011


Even though I wrote it, I don't think the clone example on the Private Names pages is very clear so I'll take another trying at explaining the conflict free extension use cases.  Just to make sure that we don't confuse things with any assumptions about the implicit semantics of a clone operation I'm going to use a method named "work" instead of "clone".

#1 A framework writer needs to add a method to object prototype. They use that method extensive internally within the framework.They assign a private name that they internally reference as 'work' for that method.  They also provide a way for client code to access that private name.  

#2 An application developer uses the framework from #1 (let's call it MF).  They are generally unaware that  MF has added an extension method to Object.prototype:
    var MF = InstallMF();
    var thing = MF.getAThing();  //behind the scene calls MF's work method

#3 The application developer for their own good reasons decides to add a method named 'work' to Object.prototype. MF internally just keeps working:
    var MF = InstallMF();
    Object.prototype.work = function () { ...};
    var thing = MF.getAThing();    //behind the scene calls MF's work method, still works fine
    var appThing = think.work();  //class the app work method.

#4 Another framework writer has also implemented method using the private name work.  The application developer decides to add that framework to the application. MF still works as does the apps own work method:
    var MF = InstallMF();
    var BF = BFLoader();
    Object.prototype.work = function () { ...};
    var thing = MF.getAThing();    //behind the scene calls MF's work method, still works fine
    var appThing = think.work();  //class the app work method.
    var bStuff = BF.buildStuff();   //behinds the scene calls BF's work method.

#5 The application writer studies the document of the MF framework and discovers that to accomplish some specific goal using the framework they need to call its work method on an object.  Because they are already using their own work method on the same objects they imports MF's work private name under another name of the apps choosing:
    var MF = InstallMF();
    var BF = BFLoader();
    Object.prototype.work = function () { ...};
    var thing = MF.getAThing();    //behind the scene calls MF's work method, still works fine
    var appThing = thing.work();  //class the app work method.
    var bStuff = BF.buildStuff();   //behinds the scene calls BF's work method.
    private workMF = MF.names.work;
    appThing.workMF();  //Explicitly  MF's work method

#6 The application writer subsequently discovers that they also need to invoke BF's work method  so they also  imports BFs work private name under another name of the apps choosing:
    var MF = InstallMF();
    var BF = BFLoader();
    Object.prototype.work = function () { ...};
    var thing = MF.getAThing();    //behind the scene calls MF's work method, still works fine
    var appThing = thing.work();  //class the app work method.
    var bStuff = BF.buildStuff();   //behinds the scene calls BF's work method.
    private workMF = MF.names.work;
    appThing.workMF();  //Explicitly  MF's work method
    private workBF = BF.getExtensionMethodName("work");
    appThing.workBF();

Note that it is only in scenarios #5 and #6  that any sort of explicit name disambiguation needs to be done.  There are situations where the app developer needs to have simultaneous access to similarly named extension methods. The disambiguation only is necessary within the local code that requires such access and the developer can choose what ever local name assignment will be most convenient and meaningful from the app perspective. 

I have a few additional comments embedded below.

 
On Mar 19, 2011, at 10:54 PM, Andrew Dupont wrote:

> On Mar 19, 2011, at 7:02 PM, Sam Tobin-Hochstadt wrote:
> 
>> You're correct -- this won't do what you probably intended.  But the
>> great thing about private names is that this is a problem you can
>> *locally* fix.  For example:
>> 
>> private myClone = installCloneLibrary();
>> var twin = [{a:0}, {b:1}].myClone();
>> var thing = MyObj.clone();
> 
> Yeah, but at that point one might as well just name the function myClone (replacing "my" with some framework-specific prefix) and eschew private names altogether. In this example, being able to name the method "clone" without fear of naming collisions is the whole point.

True, the framework could have prefixed all its internal extension methods but that is not fool proof and all internal uses of the methods may look "ugly".  From the framework perspective, you can view private names as a prefixing mechanism that guarantees you will never have conflicts with another frameworks prefixing. It also allows you to internally use pleasant, readable names.


> 
>> or
>> 
>> var cloneProp = installCloneLibrary();
>> var twin = [{a:0}, {b:1}][cloneProp]();
>> var thing = MyObj.clone();
> 
> This is more palatable, but I wager it's far harder for end-users to grok.

Which is one of the motivation for private names.  The above formulation would need to be used even when there wasn't a conflict and as you say, it is harder to grok.


> 
> Anyway, now that I've confirmed my suspicions, I'm hesitant about the private names proposal as described. The fact that declaring a certain name as private affects _all_ property name lookups in that scope (all lookups that use the dot operator or object literal syntax, at least) — well, I'm not sure I like the implications. It would mean a new  and _surprising_ distinction between dot notation and bracket notation.

There is already a distinction between dot notation and bracket notation:
  var obj = {0: "zero", foo: "foo"};
  var foo = 0;
  print ( obj.foo === obj[foo]);  //false, really obj.foo ===obj[42]


> 
> As a maintainer of a framework that does quite a bit of built-in extension, I can't imagine us using private names for this purpose. If we wanted to define {}.clone in this manner, we'd be exchanging one potential collision (one property defined in one place) for another (every property defined in the same lexical scope). If the private names had their own operator (e.g., twin#clone vs. twin.clone), it'd at least be worth considering.
> 
> I'm sure private names would be useful for other reasons, but IMO it wouldn't solve the problem of safely extending built-ins.
> 
> Cheers,
> Andrew
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss



More information about the es-discuss mailing list