Private Names and Methods

Axel Rauschmayer axel at rauschma.de
Thu Apr 5 09:17:41 PDT 2012


Aren’t you possibly overthinking the problem? Generic methods should normally only access public methods. Should you ever have different needs, you would need to come up with a more elaborate solution such as clients having to import both the generic method and the private name it uses.

On the other hand, private names are incredibly flexible in that you can easily implement any kind of “friend” (à la C++) scheme, simply by passing the name to all parties that should know about it. That means that you can, say, implement a “layer” where one fragment (=set of methods) per class among a set of classes communicates via a private protocol.

On Apr 5, 2012, at 3:27 , Kevin Smith wrote:

> Let's say that we have a class with two methods, and we divide the body of each method into abstract "regions":
> 
>     M1() {
>       <A>
>       <B>
>       <C>
>     }
> 
>     M2() {
>       <D>
>       <C>
>       <E>
>     }
> 
> Both M1 and M2 share the region <C>.  In a traditional class-based language, we would refactor <C> into an abstract operation using a private method:
> 
>     M1() {
>       <A>
>       <B>
>       this.M3();
>     }
> 
>     M2() {
>       <D>
>       this.M3();
>       <E>
>     }
> 
>     private M3() {
>       <C>
>     }
> 
> In a traditional class-based language, the refactored code will:
> 
> 1) provide an identical public interface, and
> 2) be functionally identical
> 
> These two guarantees allow us to separate interface from implementation, and to localize the implementation strategy.
> 
> Will private methods, implemented with private name objects, provide us with the same guarantees?  Let's refactor again, this time using a private name for the new method:
> 
>     // Assume that there exists a "const M3 = Name.create();" somewhere above
> 
>     M1() {
>       <A>
>       <B>
>       this[M3]();
>     }
> 
>     M2() {
>       <D>
>       this[M3]();
>       <E>
>     }
> 
>    [M3]() {
>       <C>
>     }
> 
> Since M3 is not visible to any code that does not also have a reference to the M3 private name, we can say that this refactoring provides the same public interface.  But is it functionally identical?  
> 
> Let's assume that prior to the refactoring, M1 and M2 were generic methods.  That is, they reference only properties of |this| which correspond to some subset S of the public interface of the class.  Any other object which implements S can also be used with M1 and M2 (like the generic methods defined on Array.prototype).
> 
> After the refactoring shown above, there's no possibility that M1 and M2 can be generic, since they access a privately named property of |this| which by definition is not a part of the public interface of the class.  So in this sense, the refactored code is not functionally identical to the original code.
> 
> If we wanted to preserve identical functionality, we could define M3 as a regular function and call it using the call method of Function.prototype:
> 
>     // Somewhere *before* the class definition we have:
>     function M3() {
>       <C>
>     }
> 
>     ...
> 
>     M1() {
>       <A>
>       <B>
>       M3.call(this);
>     }
> 
>     M2() {
>       <D>
>       M3.call(this);
>       <E>
>     }
> 
> The above strategy works, but (a) explicitly calling M3 via call() is awkward, and (b) it defeats the purpose of an elegant class syntax if we must refactor code into functions outside of the class definition.
> 
> Thoughts?
> 
> kevin
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

-- 
Dr. Axel Rauschmayer
axel at rauschma.de

home: rauschma.de
twitter: twitter.com/rauschma
blog: 2ality.com

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120405/5f2bd8aa/attachment.html>


More information about the es-discuss mailing list