From 8c4d88554108311e884955a98ad656cf084da37b Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Fri, 6 Apr 2012 00:10:23 -0400 Subject: [PATCH] Minor corrections to "Private Member Encapsulation" section --- coope.tex | 2 +- sec/encap-hacks.tex | 94 ++++++++++++++++++++++----------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/coope.tex b/coope.tex index 65e6656..a4e5361 100644 --- a/coope.tex +++ b/coope.tex @@ -47,7 +47,7 @@ development to include relevant information from the development of ease.js. In the meantime, the reader is welcome to browse through the technical manual for the project at \url{http://easejs.org/manual/Implementation-Details.html}. The manual contains implementation details and rationale for much of what will be -elaborated upon in this article. +elaborated upon in this paper. \bibliographystyle{plain} \bibliography{coope} diff --git a/sec/encap-hacks.tex b/sec/encap-hacks.tex index 0015903..872ee3d 100644 --- a/sec/encap-hacks.tex +++ b/sec/encap-hacks.tex @@ -296,12 +296,12 @@ recommends the implementation in \jsref{lst:new-global-fix}. \subsection{Private Member Encapsulation} Section~\ref{sec:encap} discussed the encapsulation of private member data -by means of private property and method objects, avoiding the performance impact -of privileged members (see section~\ref{sec:privileged}). In order to avoid -memory leaks, the private data was stored on the instance itself rather than a -truly encapsulated object. The amount of code required for this implementation -is relatively small, but it is still repeated unnecessarily between all -constructors. +by means of private property and method objects, thereby avoiding the +performance impact of privileged members (see section~\ref{sec:privileged}). In +order to avoid memory leaks, the private data was stored on the instance itself +rather than a truly encapsulated object. The amount of code required for this +implementation was relatively small, but it is still repeated unnecessarily +between all constructors. The private member implementation had two distinct pieces --- private properties, as demonstrated in \jsref{lst:encap-inst}, and private methods, as @@ -309,32 +309,32 @@ demonstrated in \jsref{lst:method-priv}. This distinction is important, as private methods should not be redefined for each new instance (see \fref{fig:proto-priv-cmp}). Properties, however, \emph{must} have their values copied for each new instance to prevent references from being shared between -multiple instances (see \jsref{lst:proto-reuse}; this is not an issue for -scalars). For the time being, we will focus on the method implementation and -leave the manual declaration of private properties to the \func{\_\_construct()} -method. +them (see \jsref{lst:proto-reuse}; note that this is not an issue for scalars). +For the time being, we will focus on the method implementation and leave the +manual declaration of private properties to the \func{\_\_construct()} method. The listings in section~\ref{sec:encap} were derived from a simple concept --- the private member objects were within the scope of the prototype members. -However, if we are encapsulating this hack within our constructor factory, then +However, if we are to encapsulate this hack within our constructor factory, then the members (the definition object) would be declared \emph{outside} the scope of any private member objects that are hidden within our factory. To expose the private ``prototype'' object, we could accept a function instead of a definition -object, which would expose a reference to the object (\jsref{lst:prot-func}). -However, this would be very unnatural and unintuitive. To keep our ``class'' -declarations simple, another method is needed. +object, which would expose a reference to the object (as in +\jsref{lst:prot-func}). However, this would be very unnatural and unintuitive; +to keep our ``class'' declarations simple, another method is needed. -Consider the private member concept in a classical sense --- the data should be -available only to the methods of the class, but should not be accessible outside -of them. That is, given any class \code{C} with private property \code{C.\_priv} -and public method \code{C.getPrivValue()}, and an instance \code{i} of class -\code{C}, \code{i.\_priv} should not be defined unless within the context of -\code{i.getPrivValue()}. Consider then the only means of exposing that data to -the members of the prototype in ECMAScript without use of closures: through the -instance itself (\keyword{this}). This naturally derives an implementation that -had not been previously considered due to the impracticality of its use without -an automated factory --- exposing private members before a method invocation and -revoking them after the method has returned. +Consider the private member concept in a classical sense --- the private data +should be available only to the methods of the class and should not be +accessible outside of them. That is, given any class \code{C} with private +property \code{C.\_priv} and public method \code{C.getPrivValue()}, and an +instance \code{i} of class \code{C}, \code{i.\_priv} should not be defined +unless within the context of \code{i.getPrivValue()}. Consider then the only +means of exposing that data to the members of the prototype in ECMAScript +without use of closures: through the instance itself (\keyword{this}). This +naturally derives an implementation that had not been previously considered due +to the impracticality of its use without factory --- exposing +private members before a method invocation and revoking them after the method +has returned. To accomplish this, the factory must be able to intelligently determine when a method is being invoked. This leads us into a somewhat sensitive topic --- @@ -356,13 +356,13 @@ can also be easily extended to create \dfn{partially applied functions}.} \jsref{lst:func-wrap} demonstrates the basic concept of a function wrapper. \func{wrap()} accepts a single argument, \var{func}, and returns a new anonymous -function which invokes \var{func}, returning its value with a prefix and suffix. -Note how all arguments are forwarded to \var{func}, allowing us to invoke our -wrapped function as if it were the original. Also note the context in which -\var{func} is being called (the first argument of \func{apply()}). By binding -\keyword{this} of \var{func} to \keyword{this} of our wrapper, we are -effectively forwarding it. This detail is especially important if we are using -a wrapper within a prototype, as we \emph{must} bind \keyword{this} to the +function which invokes \var{func}, returning its value with a prefix and a +suffix. Note how all arguments are forwarded to \var{func}, allowing us to +invoke our wrapped function as if it were the original. Also note the context in +which \var{func} is being called (the first argument of \func{apply()}). By +binding \keyword{this} of \var{func} to \keyword{this} of our wrapper, we are +effectively forwarding it. This detail is especially important if we are using a +wrapper within a prototype, as we \emph{must} bind \keyword{this} to the instance that the method is being invoked upon. Use of \func{wrap()} with a prototype is demonstrated in \jsref{lst:func-wrap-ex} below. @@ -388,7 +388,7 @@ decision is minimal.} \subfloat[% Wrapper performance \emph{(invocation only)}. Operations per second rounded to millions.\cite{jsperf-func-wrap} Numbers in parenthesis indicate percent - change between the two values, indicating a significant performance loss. + change between the two values, demonstrating a significant performance loss. ]{ \input{data/func-wrap-invoke.tex} \label{fig:func-wrap-perf-invoke} @@ -396,26 +396,26 @@ decision is minimal.} \quad \subfloat[% Wrapper performance \emph{with business logic} - (\code{(new Array(100)).join(',|').split('|')}); performance + (\code{(new Array(100)).join('|').split('|')}); performance impact is negligible. Operations per second.\cite{jsperf-func-wrap-blogic} ]{ \input{data/func-wrap-blogic.tex} \label{fig:func-wrap-perf-blogic} } \caption{Function wrapping performance considerations. When measuring invocation -performance, the wrapper appears to be a terrible solution to any problem. -However, when considering the business logic the remainder of the software is -likely to contain, the effects of the wrapper are negligible. As such, worrying -about the wrapper is likely to be a micro-optimization, unless dealing with -call stack limitations. The wrapper in these tests simply invokes the wrapped -method with \code{Function.apply()}, forwarding all arguments.} +performance, the wrapper appears to be prohibitive. However, when considering +the business logic that the remainder of the software is likely to contain, the +effects of the wrapper are negligible. As such, worrying about the wrapper is +likely to be a micro-optimization, unless dealing with call stack limitations. +The wrapper in these tests simply invokes the wrapped method with +\code{Function.apply()}, forwarding all arguments.} \label{fig:func-wrap-perf} \end{figure*} Many readers are likely to be concerned about a decision that wraps every function of our definition object, as this will require two function calls each -time a method is invoked. \fref{fig:func-wrap-perf-invoke} shows why this detail -is likely to be a concern --- invoking our wrapped function is so slow in +time a method is invoked. \frefpg{fig:func-wrap-perf-invoke} shows why this +detail is likely to be a concern --- invoking our wrapped function is so slow in comparison to invoking the original function directly that the solution seems prohibitive. However, one must consider how functions are \emph{actually} used --- to perform some sort of business logic. It is rare that we would invoke @@ -424,9 +424,9 @@ consideration the \emph{percent change between function invocations that contain some sort of business logic}. This is precisely what \frefpg{fig:func-wrap-perf-blogic} takes into consideration, showing that our invocation worry is would actually be a micro-optimization. For example, in -software that performs DOM manipulation, the performance impact of -wrapper invocation is likely to be negligible due to repaints being highly -intensive operations. +software that performs DOM manipulation, the performance impact of wrapper +invocation is likely to be negligible due to repaints being highly intensive +operations. One legitimate concern of our wrapper implementation, however, is limited call stack space. The wrapper will effectively cut the remaining stack space in @@ -449,8 +449,8 @@ functions and its result returned by a wrapped method call. \label{fig:stack-limits} \end{figure} -That said, call stack sizes for ECMAScript environments are growing increasingly -larger. Call stack limits for common browsers (including historical versions for +That said, call stack sizes for ECMAScript environments are growing ever larger. +Call stack limits for common browsers (including historical versions for comparison) are listed in \frefpg{fig:stack-limits}. Should this limit be reached, another alternative is to use \func{setTimeout()} to reset the stack and continue the recursive operation. This can also have the benefit of making