Fwd: An idea to extend the functionality of Proxy objects.

Ranando King kingmph at gmail.com
Mon Jan 15 15:41:31 UTC 2018


---------- Forwarded message ----------
From: Ranando King <kingmph at gmail.com>
Date: Sat, Jan 13, 2018 at 2:35 PM
Subject: Re: An idea to extend the functionality of Proxy objects.
To: Isiah Meadows <isiahmeadows at gmail.com>


Sorry clicked send before editing. The first version is the original, the
second the modified version. This this the kind of thing you were referring
to? I admit that doing this makes it more clear that the prototype handler
methods are being called, and I can see the value in doing so, but this
would indeed require a fairly large rewording to the invariant
requirements. Hopefully, however, it is clear that such a rewording doesn't
change the intent of the requirement.

On Sat, Jan 13, 2018 at 2:32 PM, Ranando King <kingmph at gmail.com> wrote:

> After thinking about it a bit more, maybe you mean something like this:
>
> [[SetPrototypeOf]] (V)
>
>    - The Type of the return value must be Boolean.
>    - If target is non-extensible, [[SetPrototypeOf]] must return false,
>    unless V is the SameValue
>    <https://tc39.github.io/ecma262/#sec-samevalue> as the target's
>    observed [[GetPrototypeOf]] value.
>
> After thinking about it a bit more, maybe you mean something like this:
>
> [[SetPrototypeOf]] (V)
>
>    - The Type of the return value must be Boolean.
>    - *If [[IsExtensible]] returns false*, [[SetPrototypeOf]] must return
>    false, unless V is the SameValue
>    <https://tc39.github.io/ecma262/#sec-samevalue> as *that returned by
>    [[GetPrototypeOf]]*.
>
>
> After thinking about it a bit more, maybe you mean something like this:
>
>
> On Sat, Jan 13, 2018 at 2:23 PM, Ranando King <kingmph at gmail.com> wrote:
>
>> While I understand what you're getting at, The invariants would *not* change
>> under my idea. In fact, I've thought about it carefully and crafted the
>> wording change from my suggestion specifically so that the invariants
>> wouldn't change. My goal is simply to change this process:
>>
>> some action on proxied target ->
>> [[ProxyHandler]] method called ->
>> [[ProxyHandler]] method results checked by testing against
>> Reflect.<methods>(target...) ->
>> error on failure -> return result
>>
>> into
>>
>> some action on proxied target ->
>> [[ProxyHandler]] method called ->
>> [[ProxyHandler]] method results checked by testing against
>> [[ProxyHandler]].<methods>(target...) ->
>> error on failure -> return result
>>
>> so that the developers proxy handler implementation is solely responsible
>> for ensuring that the invariant requirements are maintained. The <methods>
>> in question are exactly those described by the invariants. The only thing
>> that is changing is that [[ProxyHandler]] would be the authority for the
>> information used to ensure that the invariants have not been violated.
>>
>> The gist is that while currently, given a caller, a proxy, and a target,
>> the target constrains what the caller can do with the proxy, what I want is
>> to reverse it so that the proxy constrains what the caller can do with the
>> target, and all still without violating the existing invariant
>> requirements. Does that make what I'm after a little clearer?
>>
>> On Fri, Jan 12, 2018 at 9:07 PM, Isiah Meadows <isiahmeadows at gmail.com>
>> wrote:
>>
>>> Not full, but changes of some kind will likely be required, and you
>>> should address and document how those would be changed.
>>>
>>> On Fri, Jan 12, 2018, 20:41 Ranando King <kingmph at gmail.com> wrote:
>>> >
>>> > You're right about the mistake with Object.seal. I wasn't too focused
>>> on that part when writing the example code. So are you suggesting that I
>>> also prepare a fully detailed rewrite of the invariant rules for comparison?
>>> >
>>> > On Fri, Jan 12, 2018 at 6:44 PM, Isiah Meadows <isiahmeadows at gmail.com>
>>> wrote:
>>> >>
>>> >> Make sure to compare your changes to the [invariants of the essential
>>> >> internal methods][1], since changes to them would require some
>>> >> *significant* justification. And yes, your proposal would require
>>> >> changes to them. (I'm not a TC39 member, but I've read up enough about
>>> >> their decisions to make some educated guesses, and core changes tend
>>> >> to be met with extreme skepticism.)
>>> >>
>>> >> Also, note that you probably meant to, in `SourceFile.js`, use
>>> >> `Object.seal(obj)`, not `obj.seal()` (it's a static method, not an
>>> >> instance method).
>>> >>
>>> >> [1]: https://tc39.github.io/ecma262/#sec-invariants-of-the-essent
>>> ial-internal-methods
>>> >> -----
>>> >>
>>> >> Isiah Meadows
>>> >> me at isiahmeadows.com
>>> >>
>>> >> Looking for web consulting? Or a new website?
>>> >> Send me an email and we can get started.
>>> >> www.isiahmeadows.com
>>> >>
>>> >>
>>> >> On Fri, Jan 12, 2018 at 5:38 PM, Ranando King <kingmph at gmail.com>
>>> wrote:
>>> >> > I have an idea I’d like to propose with regards to Proxy objects. I
>>> would
>>> >> > like to make a change to spec section 6.1.7.3 (as seen in the
>>> latest draft).
>>> >> > The change is as follows:
>>> >> >
>>> >> > The Internal Methods of Objects of an ECMAScript engine must
>>> conform to the
>>> >> > list of invariants specified below. Ordinary ECMAScript Objects as
>>> well as
>>> >> > all standard exotic objects in this specification maintain these
>>> invariants.
>>> >> > ECMAScript Proxy objects maintain these invariants by means of
>>> runtime
>>> >> > checks on the result of traps invoked on the [[ProxyHandler]]
>>> object using
>>> >> > either the corresponding traps on the [[ProxyHandler]] should the
>>> needed
>>> >> > trap be defined, or the default internal method otherwise.
>>> >> >
>>> >> > Put simply, the change that I’m requesting would have the runtime
>>> checks
>>> >> > verify the selfconsistency of the results returned by the
>>> [[ProxyHandler]]
>>> >> > object instead of testing the [[ProxyHandler]] results against the
>>> target.
>>> >> > The rationale behind this change is to allow Proxy objects the
>>> freedom to
>>> >> > behave in a manner that is inconsistent with the behavior that
>>> would have
>>> >> > been should the target have been accessed directly, while still
>>> requiring
>>> >> > that the consistency of the behavior of the essential internal
>>> methods be
>>> >> > upheld. In this way, a Proxy object would be able to project new
>>> properties
>>> >> > for a proxied target even if the target object is not extensible,
>>> or even
>>> >> > completely hide non-configurable properties. The requirement to do
>>> so would
>>> >> > be implementation of the appropriate [[ProxyHandler]] methods so as
>>> to
>>> >> > satisfy all of the corresponding invariants for all implemented
>>> handlers.
>>> >> > The ECMAScript engine would then see results consistent with
>>> expectations,
>>> >> > despite the fact that the results are inconsistent with the actual
>>> nature of
>>> >> > the proxied target object.
>>> >> >
>>> >> > An example might be the case of a library to mock objects.
>>> >> >
>>> >> > /* SourceFile.js */
>>> >> > var obj = { bar: "The real bar. Accept no imitations!", fubar:
>>> "Always has
>>> >> > been." };
>>> >> > obj.seal();
>>> >> >
>>> >> > export default obj;
>>> >> >
>>> >> > /* TestFile.js */
>>> >> > import testObj from "SourceFile";
>>> >> >
>>> >> > var mock = new Proxy(testObj, {
>>> >> >   has: function(target, key) {
>>> >> >     var retval = false;
>>> >> >     if (key == "foo") { //add the foo property
>>> >> >       retval = true;
>>> >> >     }
>>> >> >     else if (key != "bar") { //hide the bar property
>>> >> >       retval = (key in target);
>>> >> >     }
>>> >> >
>>> >> >     return retval;
>>> >> >   },
>>> >> >   ownKeys: function(target) {
>>> >> >     var retval = Reflect.ownKeys(target);
>>> >> >     var barIndex = retval.indexOf(bar);
>>> >> >
>>> >> >     if (barIndex != -1)
>>> >> >       retval.splice(barIndex, 1);
>>> >> >
>>> >> >     retval.push("foo");
>>> >> >     return retval;
>>> >> >   },
>>> >> >   defineProperty: function(target, key, descriptor) {
>>> >> >     var retval = true;
>>> >> >     if ((key == "foo") || (key == "bar")) {
>>> >> >       retval = false;
>>> >> >     }
>>> >> >     else {
>>> >> >       Reflect.defineProperty(target, key, descriptor);
>>> >> >     }
>>> >> >
>>> >> >     return retval;
>>> >> >   },
>>> >> >   get: function(target, key) {
>>> >> >     var retval = undefined;
>>> >> >
>>> >> >     if (key == "foo") {
>>> >> >       retval = "You got the fake property!"
>>> >> >     }
>>> >> >     else if (key != "bar") {
>>> >> >       retval = Reflect.deleteProperty(target, key);
>>> >> >     }
>>> >> >
>>> >> >     return retval;
>>> >> >   },
>>> >> >   set: function(target, key, value) {
>>> >> >     var retval = false;
>>> >> >     if ((key != "foo") && (key != "bar"))
>>> >> >       retval = Reflect.set(target, key);
>>> >> >     }
>>> >> >     return retval;
>>> >> >   },
>>> >> >   deleteProperty: function(target, key) {
>>> >> >     var retval = false;
>>> >> >     if ((key != "foo") && (key != "bar"))
>>> >> >       retval = Reflect.deleteProperty(target, key);
>>> >> >     }
>>> >> >     return retval;
>>> >> >   },
>>> >> >   getOwnPropertyDescriptor: function(target, key) {
>>> >> >     var retval;
>>> >> >     if (key == "foo") {
>>> >> >       retval = {
>>> >> >         enumerable: true,
>>> >> >         writable: false,
>>> >> >         configurable: false,
>>> >> >         value: "You got the fake property!"
>>> >> >       };
>>> >> >     }
>>> >> >     else if (key != "bar") {
>>> >> >       retval = Reflect.getOwnPropertyDescriptor(target, key);
>>> >> >     }
>>> >> >     return retval;
>>> >> >   }
>>> >> > });
>>> >> >
>>> >> > console.log(mock.fubar); // "Always has been"
>>> >> > console.log(mock.foo);   // #1
>>> >> > console.log(mock.bar);   // #2
>>> >> >
>>> >> >
>>> >> > Currently, if the above code were run, an error would be thrown at
>>> comment
>>> >> > #1. Even if that line was commented out, an error would be thrown
>>> at comment
>>> >> > #2. With my proposed change, the code would run successfully.
>>> Comment #1
>>> >> > would be "You got the fake property!" and comment #2 would be
>>> undefined. As
>>> >> > a matter of completeness, if the handler only contained the "get"
>>> and "set"
>>> >> > methods, this code would throw an error just as it currently would.
>>> The
>>> >> > reason that it works with all of the handlers this that these
>>> handlers
>>> >> > ensure that a consistent description of the is being presented to
>>> the
>>> >> > interpreter since the interpreter would rely on the methods of the
>>> proxy
>>> >> > object's handler to supply the data needed to validate the response
>>> of the
>>> >> > original call.
>>> >> >
>>> >> > _______________________________________________
>>> >> > es-discuss mailing list
>>> >> > es-discuss at mozilla.org
>>> >> > https://mail.mozilla.org/listinfo/es-discuss
>>> >> >
>>> >
>>> >
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180115/895f2216/attachment-0001.html>


More information about the es-discuss mailing list