Closed casdevs closed 7 years ago
Private or protected methods in general is a controversial topic for dynamic languages. Major reasons are:
dcl
cannot access them too and apply its algorithms for method weaving, inherited calls, or general AOP.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:
pvt
as an argument, which is not free. How do we even know that we need to inject something here? By analyzing method's text? Should we pass it to all methods just in case?Obviously using arguments is not the only way to inject a variable. For example:
eval
it. While it is a perfectly valid approach, sometimes it is not desirable => it is not universal.this.private
-- it will be open for everybody.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.
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.
Would it be possible to add private member support to the library, i.e.
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