[#5] Added pre-es5 fallback section to visibility object implementation
parent
b339cf0859
commit
50da560c1f
|
@ -423,6 +423,7 @@ around them.
|
||||||
* Hacking Around the Issue of Encapsulation::
|
* Hacking Around the Issue of Encapsulation::
|
||||||
* The Visibility Object::
|
* The Visibility Object::
|
||||||
* Method Wrapping::
|
* Method Wrapping::
|
||||||
|
* Pre-ES5 Fallback::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Encapsulation In JavaScript
|
@node Encapsulation In JavaScript
|
||||||
|
@ -1427,6 +1428,118 @@ allows bypassing constructor logic and replacing methods at runtime. This is
|
||||||
useful for mocking, but a complete anti-pattern in terms of Classical
|
useful for mocking, but a complete anti-pattern in terms of Classical
|
||||||
Object-Oriented development.}
|
Object-Oriented development.}
|
||||||
|
|
||||||
|
@node Pre-ES5 Fallback
|
||||||
|
@subsection Pre-ES5 Fallback
|
||||||
|
For any system that is to remain functionally compatible across a number of
|
||||||
|
environments, one must develop around the one with the least set of features. In
|
||||||
|
the case of ease.js, this means designing around the fact that it must maintain
|
||||||
|
support for older, often unsupported, environments.@footnote{ease.js was
|
||||||
|
originally developed for use in software that would have to maintain
|
||||||
|
compatibility as far back as IE6, while still operating on modern web browsers
|
||||||
|
and within a server-side environment.} The line is drawn between ECMAScript 5
|
||||||
|
and its predecessors.
|
||||||
|
|
||||||
|
As mentioned when describing the proxy implementation (@pxref{Property
|
||||||
|
Proxies}), ease.js's ability to create a framework that is unobtrusive and
|
||||||
|
fairly easy to work with is attributed to features introduced in ECMAScript 5,
|
||||||
|
primarily getters and setters. Without them, we cannot proxy between the
|
||||||
|
different visibility layers (@pxref{Visibility Object Implementation}). As a
|
||||||
|
consequence, @emph{we cannot use visibility layers within a pre-ES5
|
||||||
|
environment}.
|
||||||
|
|
||||||
|
This brings about the subject of graceful feature degradation. How do we fall
|
||||||
|
back while still allowing ease.js to operate the same in both environments?
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Because getters/setters are unsupported, we cannot proxy (@pxref{Property
|
||||||
|
Proxies}) between visibility layers (@pxref{Visibility Object Implementation}).
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Visibility support is enforced for development, but it is not necessary in a
|
||||||
|
production environment (unless that environment makes heavy use of 3rd party
|
||||||
|
libraries that may abuse the absence of the feature).
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Therefore, the feature can be safely dropped.
|
||||||
|
@item
|
||||||
|
It is important that the developer develops the software in an ECMAScript 5+
|
||||||
|
environment to ensure that the visibility constraints are properly enforced.
|
||||||
|
The developer may then rest assured that their code will work properly in
|
||||||
|
pre-ES5 environments (so long as they are not using ES5 features in their
|
||||||
|
own code).
|
||||||
|
@end itemize
|
||||||
|
@end itemize
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@subsubsection Visibility Fallback
|
||||||
|
Visibility fallback is handled fairly simply in ease.js polymorphically with the
|
||||||
|
@code{FallbackVisibilityObjectFactory} prototype (as opposed to
|
||||||
|
@code{VisibilityObjectFactory} which is used in ES5+ environments), which does
|
||||||
|
the following:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Property proxies are unsupported. As such, rather than returning a proxy object,
|
||||||
|
@code{createPropProxy()} will simply return the object that was originally
|
||||||
|
passed to it.
|
||||||
|
@item
|
||||||
|
This will ultimately result in each layer (public, protected and private)
|
||||||
|
referencing the same object (the class prototype, also known as the ``public''
|
||||||
|
layer).
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Consequently, all members will be public, just as they would have been without
|
||||||
|
visibility constraints.
|
||||||
|
@end itemize
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Classical Object-Oriented programming has many rich features, but many of its
|
||||||
|
``features'' are simply restrictions it places on developers. This simple fact
|
||||||
|
works to our benefit. However, in this case of a visibility implementation, we
|
||||||
|
aren't dealing only with restrictions. There is one exception.
|
||||||
|
|
||||||
|
Unfortunately, this necessary fallback introduces a startling limitation:
|
||||||
|
Consider what might happen if a subtype defines a private member with the same
|
||||||
|
name as the supertype. Generally, this is not an issue. Subtypes have no
|
||||||
|
knowledge of supertypes' private members, so there is no potential for conflict.
|
||||||
|
Indeed, this is the case with our visibility implementation (@pxref{Visibility
|
||||||
|
Object Implementation}. Unfortunately, if we merge all those layers into one,
|
||||||
|
we introduce a potential for conflict.
|
||||||
|
|
||||||
|
@subsubsection Private Member Dilemma
|
||||||
|
With public and protected members (@pxref{Access Modifiers}), we don't have to
|
||||||
|
worry about conflicts because they are inherited by subtypes
|
||||||
|
(@pxref{Inheritance}). Private members are intended to remain distinct from any
|
||||||
|
supertypes; only that specific class has access to its own private members. As
|
||||||
|
such, inheritance cannot be permitted. However, by placing all values in the
|
||||||
|
prototype chain (the public layer), we are permitting inheritance of every
|
||||||
|
member. Under this circumstance, if a subtype were to define a member of the
|
||||||
|
same name as a supertype, it would effectively be altering the value of its
|
||||||
|
supertype. Furthermore, the supertype would have access to the same member,
|
||||||
|
allowing it to modify the values of its @emph{subtypes}, which does not make
|
||||||
|
sense at all!
|
||||||
|
|
||||||
|
This means that we have to place a certain restriction on ease.js as a whole; we
|
||||||
|
must prevent private member name conflicts even though they cannot occur in ES5
|
||||||
|
environments. This is unfortunate, but necessary in order to ensure feature
|
||||||
|
compatibility across the board. This also has the consequence of allowing the
|
||||||
|
system to fall back purely for performance benefits (no overhead of the
|
||||||
|
visibility object).
|
||||||
|
|
||||||
|
@subsubsection Forefitting Fallbacks
|
||||||
|
Although ease.js allows flexibility in what environment one develops for, a
|
||||||
|
developer may choose to support only ES5+ environments and make use of ES5
|
||||||
|
features. At this point, the developer may grow frustrated with ease.js limiting
|
||||||
|
its implementation for pre-ES5 environments when their code will not even run in
|
||||||
|
a pre-ES5 environment.
|
||||||
|
|
||||||
|
For this reason, ease.js may include a feature in the future to disable these
|
||||||
|
limitations on a class-by-class@footnote{Will also include traits in the
|
||||||
|
future.} basis in order to provide additional syntax benefits, such as omission
|
||||||
|
of the static access modifiers (@pxref{Static Implementation}) and removal of
|
||||||
|
the private member conflict check.
|
||||||
|
|
||||||
|
|
||||||
@node Internal Methods/Objects
|
@node Internal Methods/Objects
|
||||||
@section Internal Methods/Objects
|
@section Internal Methods/Objects
|
||||||
|
|
Loading…
Reference in New Issue