ES3.1 Object static methods rationale document
brendan at mozilla.org
Wed Jul 16 10:53:23 PDT 2008
On Jul 16, 2008, at 8:28 AM, Allen Wirfs-Brock wrote:
> I didn't specifically respond to that thread because I wasn't aware
> of it. I had intended to mention __proto__ as a precedent but it
> slipped through the cracks.
No problem. I wanted to point it out so that the rationale doc might
> It's true that __proto__ or getPrototypeOf breaks an object's
> encapsulation barrier and reveals implementation details that
> perhaps were intended to be hidden. The same could be said about
> the proposed getProperty function which, among other things, gives
> an observer access to the functions that implement a getter/setter
> property. In general, that's the nature of reflection. Overall, I
> think that this is a situation that is inherent in our current
> generation of dynamic languages. They tend to depend upon the use
> of idioms that require penetration of the encapsulation barrier.
Yeah, I mentioned that in the thread. It's more fundamental than a
temporary lack of the current generation of dynamic langauges.
Reflection breaks abstraction, removing some free theorems -- news at
> Some of the concerns expressed in that thread are address by other
> aspects of the static Object methods proposal. For example, the
> integrity of prototype objects can be protected by sealing them in
> whole or in part to prevent tampering.
This is a good point. SpiderMonkey and Rhino have had Seal APIs for
years for this reason (shared prototypes across thread and trust
boundaries must be immutable).
One feature of both Seal APIs is the ability to seal an entire object
graph. This is a sharp tool, since most graphs are fully connected
and if you seal the world, life gets boring fast. But it is handy for
setting up sealed standard object constructors/prototypes/methods
trees with one API call, at the beginning of the world in a throwaway
global object that (because of [[Scope]] links) gets sealed too due
to the transitive closure.
> Also note, that while we support inspection of the prototype value,
> we don't support modification of it.
I noticed ;-).
> As Doug implies below, one reason for making these operations
> "static methods" was to make it easier to control access to them.
> It you are creating some sort of sandbox, you may not want to make
> them available within it.
Yes, the static Object method suite is a good idea for that reason,
as well as for not intruding on the prototype-delegated property
space of all objects.
> That could be taken as a argument in favor of hanging them off of
> a dedicated global Meta object rather than off of Object. It may
> be slightly easier to wholesale restrict access to Meta than it
> would be to restrict access to just these methods while still
> providing access to the Object constructor.
Let's not bring back Meta to ES3.1, it is not wanted in ES4.
We should reconcile strict modes too, but that's a different topic --
except insofar as 3.1's strict mode locks down Object.defineProperty,
Object.getPrototypeOf, etc. So the host code that removes
Object.getPrototypeOf from a guest's sandbox can't be running in
strict mode. I'm not suggesting this is a problem, just noting it.
> Another already available technique for obtaining the same
> information in many situations that wasn't mentioned in the thread
> is to use Object.prototype.isPropertyOf as a probe to discover the
> prototypes of objects. It isn't something that you would want to do
> in production code but I don't think that anyone who was trying to
> crack an application would hesitate from doing.
Searching the reachable object graph would not only be time-
consuming, it could fail to find prototypes that were hidden in
disconnected components. The case of an otherwise-unreachable
prototype object was discussed in that thread.
> Arguably, some of the need for direct prototype access is
> alleviated by providing the clone method. However, there are still
> plenty of other situations where it is useful.
I observe that __proto__ in SpiderMonkey- and Rhino-based JS is
mostly used for cases covered by Object.create, with a minority use-
case that we've discussed before initializing it to null in object
initialisers to make maps (dictionaries).
I'm convinced based on this experience that __proto__ is the tempting
but wrong low-level "API" to handle these use-cases. I'm in favor of
the higher level APIs such as create, clone, and ES4 Map or similar,
provided they have the sweet syntax needed to keep kids off the
attractive nuisances with which they compete.
> Crossing the object implementation boundary is generally required
> for defining object abstractions in this language
Not generally. Constructor functions and .prototype properties go a
long way, and no one has been able to use __proto__ in portable JS on
the web, yet life goes on -- and people do define a great many object
abstractions in JS libraries.
> In summary, not providing reflective access to an object's
> prototype doesn't really provide any real security, it just makes
> some useful tasks less convenient.
I agree with you here in general, and it's good to hear that
reflection is not the enemy of "real security".
More information about the Es4-discuss