uhop / dcl

Elegant minimalistic implementation of OOP with mixins + AOP in JavaScript for node.js and browsers.
http://www.dcljs.org/
Other
76 stars 10 forks source link

Supporting private members #10

Closed casdevs closed 7 years ago

casdevs commented 10 years ago

Would it be possible to add private member support to the library, i.e.

var myType = dcl(
    null,
    {
        constructor: function()
        {
            //some way to access private members, e.g. via closure or this.private or something...          
        },

        publicFunction: function()
        {
            //some way to access private members, e.g. via closure or this.private or something...          

            return 'abc';
        },

        publicVariable: 'abc',

        private:
        {
            privateFunction: function()
            {
                return 'xzy'
            }

            privateVariable: 'xyz'
        }   
    }
);

myInstance = new myType();

console.log(myInstance.publicFunction());
--> abc

console.log(myInstance.publicVariable);
--> abc

console.log(myInstance.privateFunction());
--> undefined

console.log(myInstance.privateVariable);
--> undefined

or would there be any problems implementing such an extension with the current library's architecture?

If so, how would you recommend dealing with encapsulating private members so that they cannot be accessed from outside? I know JavaScript doesn't support the concept of private members natively, but given that your library already adds a lot of object oriented fashion, I would find it very useful to have the ability to more "encapsulate" things in larger projects....

Best regards, Stefan

uhop commented 10 years ago

Private or protected methods in general is a controversial topic for dynamic languages. Major reasons are:

In practice working on big projects I saw the same pattern over and over again: a project needs minor modifications in a 3rd-party component, but that component doesn't have proper "extension points" either by poor design, or an excessive "security" restrictions, so programmers either modify the code of component, or clone it in their own namespace and modify there. The result was always the same: major pain upgrading that component to a newer version, when new features or security fixes were added.

In practice we should delineate public and private methods and properties, and one time-honored way to do it is "by convention", e.g., by assigning different names so a user knows immediately that this stuff is private. One common convention is to start names of private API components with _. The next JavaScript standard goes even further by introducing a concept of private names -- the idea here is to use a unique/random name, which is unknown to a user.

Having said all that I don't think that this is a solved problem, I think there is something we can do in this area. dcl is essentially a thin layer on top of a native delegation mechanism. It provides helpers to create new constructors using mixins, and weaving methods. It is conceivable that it does its work, then hides already prepared methods from a public API. The big questions are: how does it hide private methods exactly, and how do other methods access them? It should be convenient for a user, and efficient for a computer.

From the top of my head, we can collect all private methods in a separate object and pass it to methods, that need them, like so:

method: function(pvt, a, b){
  // we will use a private method called add()
  return pvt.add(a, b);
}

We can do it using a pattern similar to superCall():

method: dcl.usePrivate(function(pvt){
  return function(a, b){
    return pvt.add(a, b);
  };
})

Both versions have technical and usability problems:

Obviously using arguments is not the only way to inject a variable. For example:

To sum it up: it is a complex problem, and I welcome all feedback. Thank you for bringing this problem up. This ticket will be open to collect possible ideas to be addressed as soon as we are comfortable with a solution.

uhop commented 7 years ago

It looks like ECMAScript is going to have private members: https://github.com/tc39/proposal-class-fields

Let's plan to use those rather than reinvent the wheel.

But, if there are proved to be insufficient, or never make it to the standard, we'll revisit this ticket.