Re: Proxies and preventExtensions: how to avoid inconsistency in a membrane?

2016-09-04 Thread Tom Van Cutsem
Hi Alex,

The problems you are seeing are inherent to what you're trying to achieve.
You're trying to build an abstraction (virtual extension properties that
should continue to work even on non-extensible objects) that are directly
in conflict with ES's invariants (e.g. if the object is truly
non-extensible, it shouldn't be able to report additional properties,
virtual or not (because the client can't tell the difference between an
extension property and a normal property, and we're trying to protect
clients from unexpected proxy behavior).

For the specific case of extension properties, the better alternative is to
simply let the untrusted code use WeakMaps to attach properties to objects
it doesn't control. Sadly the syntax is not as sweet as `obj[prop]`, but
this approach does completely sidestep the invariant issues (it's perfectly
fine to associate frozen objects with additional state via a WeakMap).

Essentially, if you want to implement a membrane that works in the face of
ES invariants, you need to use the "shadow target" technique where the
membrane proxy is not directly targeting the "real" target object but
instead a "dummy" target object that it can use to be more flexible in what
it can answer. It seems that is more or less the solution you stumbled
upon. See <
https://github.com/tvcutsem/harmony-reflect/blob/master/examples/generic_membrane.js>
for a membrane implementation that works this way.

I'm writing to ask the following:
>
>1. Are there other options for the given problem that I am not seeing?
>
> To my knowledge, the shadow target technique is the only way to build
proxies that need to be able to do more than their real target allows.

>
>1. Could the existing ProxyHandler part of the spec be extended, so
>that in the future I could override that invariant (and others, yet
>undetermined) explicitly?
>
> What do you mean by "override that invariant"? By definition, an invariant
can't be overridden. Otherwise it's no longer an invariant.


>
>1. Could there be a Proxy.hasBeenRevoked(proxy) method?
>
> I don't see why you would need this. Note that revokable proxies can't be
just revoked by any other object: on creation, the code that creates the
proxy (presumably the membrane) is the only code that has access to the
revoke function. Thus, it is always possible for the creator of the proxy
to wrap the proxy's revoke function with additional actions that would need
to occur before or after revocation, and share only the wrapped revoke
function with the outside world.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: The Invariants of the Essential Methods are false in case of reentrancy

2016-08-11 Thread Tom Van Cutsem
I don't think it's too worrisome because of the following reasoning:

Any code prior to the first invocation of obj.x (let's call this the "outer
code") will have observed the property as configurable & writable, so
having obj.x evaluate to 1 is a valid outcome.

Any code that runs synchronously between the call to Object.defineProperty
and the `return 1` statement (let's call this the "inner code"), will
consistently observe obj.x as non-configurable,non-writable and will always
read 2.

A worrisome scenario would be when the inner code computes results based on
the new value of x that are also accessible to the outer code, and the
outer code somehow expects that value to be consistent with the old value
of x. However, it's unclear that this bug is really due to the violation of
an ES invariant.

I'm not sure if proxies would amplify the problem. Actually, the invariant
assertions in the Proxy internal methods were designed precisely to avoid
such bugs, which is why all the assertions trigger when the trap has
finished executing and the proxy can no longer influence the outcome of the
intercepted operation. The bug described above would be avoided if the
internal methods of Ordinary ES objects would apply the same kind of
invariant checks as proxies do, checking the result of the [[Get]]
operation with the property's current attribute state. However, I suspect
that would probably be a bridge too far in terms of cost vs payoff.

Regards,
Tom


2016-08-10 17:51 GMT+02:00 Claude Pache :

> Test case:
>
> ```js
> var results = []
>
> var observe = function (method, object, ...args) {
> results.push({
> method: method
>   , object: object
>   , args: args
>   , output: Reflect[method](object, ...args)
> })
> }
>
> var obj = { get x() {
> Object.defineProperty(this, 'x', { value: 2, configurable: false,
> writable: false })
> observe('getOwnPropertyDescriptor', this, 'x')
> return 1
> } }
>
> observe('get', obj, 'x')
>
> results[0]
> // { method: "getOwnPropertyDescriptor", object: obj, args: [ "x" ],
> output: { value: 2, writable: false, enumerable: true, configurable: false
> } }
> // `obj` is observed to have a nonconfigurable, nonwritable property "x"
> with value `2`.
>
> results[1] // { method: "get", object: obj, args: [ "x" ], output: 1 }
> // Then, `obj.[[Get]]("x") is observed to return `1`.
> ```
>
> Not sure if it is worrisome. What is sure, the situation could become
> worse with fanciful proxies.
>
> ―Claude
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.freezing proxies should freeze or throw?

2016-08-10 Thread Tom Van Cutsem
Thanks Claude for your careful review, and for trying to articulate a more
general principle behind the invariant checks. The lack of such crisp
principles makes it (too) difficult to verify whether all necessary checks
are in place.

To clarify, in the case of "update" MOP operations such as defineProperty
and deleteProperty, your "state B" (the observable state of the target),
presumably is the state of the target *after* the proxy trap has executed,
i.e. state B should already reflect the update.

Both the original issue and your new test case with deleteProperty are
cases where the proxy pretends to have altered the target but has in fact
not. In a later interaction, the proxy reverts to the original state. This
violates a client's expectations about when state transitions occur.

Interestingly, the opposite problem, where a proxy does alter the target as
requested, but then reports that the update failed, is allowed, even though
this technically also violates a client's expectations about what state
transitions have occurred. But a failed update leads to a TypeError anyway.

At this point, we should probably iron out the details of the fix in a
GitHub issue or on bugs.ecmascript.org.

Cheers,
Tom

2016-08-09 14:44 GMT+02:00 Claude Pache :

> Given a Proxy that pretends to be in state A while its target is
> observably in state B, and assuming that the target satisfies the
> Invariants of the Essential Internal Methods [6.1.7.3], I claim that, in
> order to force the Proxy to satisfy those Invariants, it is necessary and
> sufficient to check that the two following conditions hold:
>
> * it is legal for an object to pass from state A to state B; and,
> * it is legal for an object to pass from state B to state A.
>
> [6.1.7.3]: https://tc39.github.io/ecma262/#sec-invariants-of-
> the-essential-internal-methods
>
>
> Because I am too lazy to write the proof just now, I cowardly leave it as
> an exercice to the reader. Meanwhile, that principle may be used to audit
> the robustness of the Proxy specification. I have found the following bug
> in Proxy.[[Delete]]() by applying the above principle to:
>
> * state A: nonexistent property on a nonextensible object;
> * state B: existent own property on a nonextensible object.
>
> Resurrection of a successfully deleted property on a nonextensible object:
>
> ```js
> var target = Object.preventExtensions({ x: 1 })
> var proxy = new Proxy(target, {
> deleteProperty() { return true }
> })
>
> Object.isExtensible(proxy) // false
> delete proxy.x // true
> proxy.hasOwnProperty('x') // true
> ```
>
> After a first scan, I haven't found other bugs in the essential methods of
> Proxy, than that one and the missing nonconfigurable-but-writable check in
> [[GetOwnPropertyDescriptor]] and [[DefineOwnProperty]] already mentioned in
> that thread.
>
> I plan to propose a minimal patch (i.e., just adding the missing checks)
> in a few days.
>
> —Claude
>
>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.freezing proxies should freeze or throw?

2016-08-08 Thread Tom Van Cutsem
I just realized: since the tightened test is reading Desc.[[Writable]] but
Desc can by any descriptor, we probably need to first check whether Desc is
a DataDescriptor and disregard the writability test otherwise.

2016-08-08 22:35 GMT+02:00 Tom Van Cutsem <tomvc...@gmail.com>:

> Claude's additional example is indeed evidence that Object.freeze is not
> to blame, but rather that the invariant checks of
> [[GetOwnPropertyDescriptor]] and [[DefineOwnProperty]] are too weak. The
> culprit is, as far as I can tell, that we re-used the state transitions
> allowed by DefineOwnProperty, which allows the transition from
> non-configurable,writable (-c+w) to non-configurable,non-writable (-c-w)
> and which is unwanted here, as Claude rightfully concludes *[to better
> understand the state transitions involved, see MarkM's lucid state
> transition chart of property attributes
> <http://wiki.ecmascript.org/doku.php?id=es3.1:attribute_states
> <http://wiki.ecmascript.org/doku.php?id=es3.1:attribute_states>>. I wish
> this diagram were in the spec btw, once you know how to read it, it is
> significantly easier to understand than the DefineOwnProperty algorithm
> itself]*
>
> I like the simplicity of Claude's suggestion, but I think that check is
> too tight. Technically if the descriptors are both -c+w data descriptors,
> their value attributes need not be identical to honor the spec invariants.
> Instead I would propose to tackle the problem head-on and explicitly
> disallow a proxy from reporting a -c-w property if the corresponding target
> property is -c+w. We already have a similar check in place in precisely
> those two algorithms to test if the configurable attribute matches. It is
> just a matter of tightening that check to also verify the writable
> attribute.
>
> This would entail the following changes to the ES2015 spec (new or
> modified text in bold):
>
>
> 9.5.5 [[GetOwnProperty]] (P)
>   ...
>   22. If resultDesc.[[Configurable]] is false, then
> a. If targetDesc is undefined or targetDesc.[[Configurable]] is true,
> then
>   i. Throw a TypeError exception.
> *b. If resultDesc.[[Writable]] is false and targetDesc.[[Writable]] is
> true, then*
> *  i. Throw a TypeError exception.*
>
> NOTE [[GetOwnProperty]] for proxy objects enforces the following
> invariants:
>
>   ...
> *  * A property cannot be reported as non-configurable, non-writable if it
> exists as a non-configurable, writable own property on the target object.*
>
>
> 9.5.6 [[DefineOwnProperty]] (P, Desc)
>   ...
>   20. Else targetDesc is not undefined,
> a.  If IsCompatiblePropertyDescriptor(extensibleTarget, Desc ,
> targetDesc) is false, throw a TypeError exception.
> *b. If settingConfigFalse is true*
> *  i. If targetDesc.[[Configurable]] is true, throw a TypeError
> exception.*
> *  ii. If Desc.[[Writable]] is false and targetDesc.[[Writable]] is
> true, throw a TypeError exception.*
>
> NOTE [[DefineOwnProperty]] for proxy objects enforces the following
> invariants:
>
>   ...
> *  * A property cannot be successfully set to non-configurable,
> non-writable if the corresponding own property of the target object is
> non-configurable, writable.*
>
> WDYT?
>
> Regards,
> Tom
>
> 2016-08-08 15:37 GMT+02:00 Claude Pache <claude.pa...@gmail.com>:
>
>>
>> > Le 8 août 2016 à 11:02, Claude Pache <claude.pa...@gmail.com> a écrit :
>> >
>> > Here is another test case, with [[GetOwnPropertyDescriptor]]:
>> >
>> > ```js
>> > var target = Object.seal({x: 2});
>> > var proxy = new Proxy(target, {
>> >getOwnPropertyDescriptor(o, p) {
>> >var d = Reflect.getOwnPropertyDescriptor(o, p)
>> >if (d && 'writable' in d)
>> >d.writable = false
>> >return d
>> >}
>> > });
>> >
>> > Object.getOwnPropertyDescriptor(proxy, 'x'); // { value: 2, writable:
>> false, configurable: false }
>> >
>> > Object.defineProperty(proxy, 'x', { value: 3 })
>> >
>> > Object.getOwnPropertyDescriptor(proxy, 'x'); // { value: 3, writable:
>> false, configurable: false }
>> > ```
>> >
>> > IMHO, the most robust fix is the following: Both the
>> [[DefineOwnProperty]] and the [[GetOwnPropertyDescriptor]] contain the
>> following check:
>> >
>> > * If IsCompatiblePropertyDescriptor(extensibleTarget, resultDesc,
>> targetDesc) is false, throw a TypeError exception.
>> >
>> > I think there should be also the following check (except when
>> targetDesc is undefined, in which case an

Re: Object.freezing proxies should freeze or throw?

2016-08-08 Thread Tom Van Cutsem
Claude's additional example is indeed evidence that Object.freeze is not to
blame, but rather that the invariant checks of [[GetOwnPropertyDescriptor]]
and [[DefineOwnProperty]] are too weak. The culprit is, as far as I can
tell, that we re-used the state transitions allowed by DefineOwnProperty,
which allows the transition from non-configurable,writable (-c+w) to
non-configurable,non-writable (-c-w) and which is unwanted here, as Claude
rightfully concludes *[to better understand the state transitions involved,
see MarkM's lucid state transition chart of property attributes
>. I wish
this diagram were in the spec btw, once you know how to read it, it is
significantly easier to understand than the DefineOwnProperty algorithm
itself]*

I like the simplicity of Claude's suggestion, but I think that check is too
tight. Technically if the descriptors are both -c+w data descriptors, their
value attributes need not be identical to honor the spec invariants.
Instead I would propose to tackle the problem head-on and explicitly
disallow a proxy from reporting a -c-w property if the corresponding target
property is -c+w. We already have a similar check in place in precisely
those two algorithms to test if the configurable attribute matches. It is
just a matter of tightening that check to also verify the writable
attribute.

This would entail the following changes to the ES2015 spec (new or modified
text in bold):


9.5.5 [[GetOwnProperty]] (P)
  ...
  22. If resultDesc.[[Configurable]] is false, then
a. If targetDesc is undefined or targetDesc.[[Configurable]] is true,
then
  i. Throw a TypeError exception.
*b. If resultDesc.[[Writable]] is false and targetDesc.[[Writable]] is
true, then*
*  i. Throw a TypeError exception.*

NOTE [[GetOwnProperty]] for proxy objects enforces the following invariants:

  ...
*  * A property cannot be reported as non-configurable, non-writable if it
exists as a non-configurable, writable own property on the target object.*


9.5.6 [[DefineOwnProperty]] (P, Desc)
  ...
  20. Else targetDesc is not undefined,
a.  If IsCompatiblePropertyDescriptor(extensibleTarget, Desc ,
targetDesc) is false, throw a TypeError exception.
*b. If settingConfigFalse is true*
*  i. If targetDesc.[[Configurable]] is true, throw a TypeError
exception.*
*  ii. If Desc.[[Writable]] is false and targetDesc.[[Writable]] is
true, throw a TypeError exception.*

NOTE [[DefineOwnProperty]] for proxy objects enforces the following
invariants:

  ...
*  * A property cannot be successfully set to non-configurable,
non-writable if the corresponding own property of the target object is
non-configurable, writable.*

WDYT?

Regards,
Tom

2016-08-08 15:37 GMT+02:00 Claude Pache :

>
> > Le 8 août 2016 à 11:02, Claude Pache  a écrit :
> >
> > Here is another test case, with [[GetOwnPropertyDescriptor]]:
> >
> > ```js
> > var target = Object.seal({x: 2});
> > var proxy = new Proxy(target, {
> >getOwnPropertyDescriptor(o, p) {
> >var d = Reflect.getOwnPropertyDescriptor(o, p)
> >if (d && 'writable' in d)
> >d.writable = false
> >return d
> >}
> > });
> >
> > Object.getOwnPropertyDescriptor(proxy, 'x'); // { value: 2, writable:
> false, configurable: false }
> >
> > Object.defineProperty(proxy, 'x', { value: 3 })
> >
> > Object.getOwnPropertyDescriptor(proxy, 'x'); // { value: 3, writable:
> false, configurable: false }
> > ```
> >
> > IMHO, the most robust fix is the following: Both the
> [[DefineOwnProperty]] and the [[GetOwnPropertyDescriptor]] contain the
> following check:
> >
> > * If IsCompatiblePropertyDescriptor(extensibleTarget, resultDesc,
> targetDesc) is false, throw a TypeError exception.
> >
> > I think there should be also the following check (except when targetDesc
> is undefined, in which case another appropriate check is used):
> >
> > * If IsCompatiblePropertyDescriptor(extensibleTarget, targetDesc,
> resultDesc) is false, throw a TypeError exception.
> >
> > That would replace the weaker adhoc check about the [[Configurable]]
> attribute (search for settingConfigFalse) in those algorithms.
> >
> > (Alternatively, in order to avoid double checks, define an
> AreBothWaysCompatiblePropertyDescriptors(extensibleTarget, desc1, desc2)
> abstract operation.)
> >
> > —Claude
> >
>
> Looking closer, it seems that using IsCompatiblePropertyDescriptor is in
> fact an overkill, because we probably don’t want the special case of
> conditionally mutable [[Writable]] attribute for nonconfigurable properties.
>
> That is, I think that the following condition must hold: If either the
> target has a nonconfigurable property, or the proxy claims to have a
> nonconfigurable property, then every attribute of the property descriptor
> claimed by the proxy must be identical to the 

Re: Object.freezing proxies should freeze or throw?

2016-08-07 Thread Tom Van Cutsem
Good catch. This appears to be a genuine spec bug.

First, I thought that the problem simply was due to sloppy-mode silent
failures, as a call to Object.isFrozen revealed that the proxy is not
actually frozen after the call to Object.freeze. When your script is run in
strict mode, it fails:

on Chrome: Uncaught TypeError: 'set' on proxy: trap returned falsish for
property 'x'
on Firefox: TypeError: proxy set handler returned false for property '"x"'

However, this error can easily be avoided by adding a `return true` to the
set trap. At this point, your example still runs in strict mode, which
worried me.

The culprit is not that the proxy's "x" property can still be updated, but
rather that Object.freeze(proxy) doesn't actually freeze the proxy yet
still returns without throwing. Thus, a shorter testcase of the problem is:

  "use strict";
  const target = Object.seal({x: 2});
  const proxy = new Proxy(target, {
defineProperty() {
  return true;
}
  });
  Object.freeze(proxy);
  console.log(Object.isFrozen(proxy)); // expected true, but is false

Tracing through the ES2015 spec, the spec 'call stack' is roughly:

19.1.2.5 Object.freeze ( O )
calls 7.3.14 SetIntegrityLevel (O, level = "frozen")
 calls 7.3.7 DefinePropertyOrThrow (O, P = "x", desc = {configurable:
false, writable: false})
  calls 9.5.6 [[DefineOwnProperty]] (P, Desc)
   calls 9.1.6.2 IsCompatiblePropertyDescriptor (Extensible, Desc, Current)
calls 9.1.6.3 ValidateAndApplyPropertyDescriptor (O, P, extensible,
Desc, current)
 where O = undefined, P = undefined, extensible = false,
Desc = {configurable: false, writable: false},
current = { value: 2, writable: true, enumerable: true,
configurable: false }

The ValidateAndApplyPropertyDescriptor, when called via
IsCompatiblePropertyDescriptor, essentially checks whether it is legal to
update an existing property descriptor `current` to a new state described
by `Desc`, without actually performing the update.

Tracing through the details of that algorithm, it turns out the above
property descriptors are indeed compatible. It is legal to update a data
property {writable: true, configurable: false} to {writable: false,
configurable: false}. IIRC, this is somewhat of an exception as it is the
only state transition allowed on a non-configurable data property.

Because IsCompatiblePropertyDescriptor returns true, the
[[DefineOwnProperty]] call on the proxy completes successfully, signaling
to SetIntegrityLevel that the property appears to be successfully updated
to {configurable: false, writable: false} (even though it didn't in this
case, as the proxy's "defineProperty" trap simply returned `true` without
actually performing the update).

The quick fix appears to be to change the SetIntegrityLevel algorithm as
follows, by updating step 10:

10. If O is a Proxy, return TestIntegrityLevel(O, "frozen"), otherwise
return true.

With this change, the call to SetIntegrityLevel ends with a call to
TestIntegrityLevel, which will notice that O is in fact not frozen and thus
cause the call to Object.freeze to fail.

To summarize: the error here is not with the proxy invariant checks (the
proxy is still unfrozen), but rather that because of the exceptional
allowed state transfer from writable,non-configurable to
non-writable,non-configurable, SetIntegrityLevel fails to detect that the
proxy object being frozen in fact remains unfrozen.

Cheers,
Tom

2016-08-06 21:09 GMT+02:00 Raul-Sebastian Mihăilă :

> Initially posted on github (https://github.com/tc39/ecma262/issues/652),
> but I think the mailing list is more appropriate.
>
> Usually methods on Object that change some internal state of the
> objects/properties of the objects either succeed or throw. However,
> Object.freeze can fail to freeze proxies without throwing:
>
> ```js
>   const target = Object.seal({x: 2});
>   const proxy = new Proxy(target, {
> defineProperty() {
>   return true;
> },
>
> set(target, prop, value) {
>   target[prop] = value;
> }
>   });
>
>   Object.freeze(proxy);
>   console.log(proxy.x); // 2
>   proxy.x = 100;
>   console.log(proxy.x); // 100
> ```
>
> Should this be allowed?
>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Exporting ES tests to a webpage environment?

2016-08-04 Thread Tom Van Cutsem
Hi Alex,

Unfortunately I can't give you any advice on how to customize the test
suites you referred to, but I can confirm that it is indeed no accident
that the Reflect and ProxyHandler APIs are alike. They were designed such
that a proxy handler trap can easily perform the "default behavior" of the
intercepted operation, by calling the Reflect method with the same name,
passing along the same arguments. Indeed, the "double lifting" trick [1]
crucially depends on this consistency.

Cheers,
Tom

[1] https://gist.github.com/tvcutsem/6536442

2016-07-27 19:20 GMT+02:00 Alex Vincent <ajvinc...@gmail.com>:

> I'm wondering how I could test a custom implementation of a ECMAScript
> standard API in a web browser, against existing test suites that might not
> run in a browser.
>
> 
>
> I've been re-exploring implementing a Membrane, which Tom van Cutsem
> introduced to me through blogs and this mailing list a few years ago.
> (Thanks, Tom!)  So at the moment, I'm working on implementing my own module
> code based on the latest published and approved standards, which are
> slightly different than what Tom had to work with.
>
> Along the way, I happily discovered the Reflect object's API matches the
> ProxyHandler's API.  That can't be by accident. I suspect SpiderMonkey's
> Reflect implementation is probably very close to the standard, given the
> usual high quality of their work and good number of tests they have in
> their codebase. [1]  That, plus the TC39 tests, [2] give me confidence that
> the native Reflect implementation I use in a Firefox-derived application
> will be quite good.  Combined with WeakMap, it should make a basic Membrane
> implementation relatively easy.
>
> With that said, I think I will run into complications when I try to
> introduce other ideas, such as hiding properties.  So I may have to write a
> custom Reflect implementation.  That implementation will in some cases just
> call the native Reflect API.  But in other cases I suspect I will need a
> little more detailed information, like "Which object in the prototype chain
> actually implements that named property?"
>
> Plus, I will probably have some debug-logging to do, as Firefox's debugger
> doesn't like to step through proxy handler code.  (I have to look for an
> existing bug on that, or file one.  It's easy to reproduce.)
>
> 
>
> The good news is, I suspect I can run a custom Reflect against existing
> code, loaded in a webpage, by wrapping it in function(Reflect) { ... }.
> The bad news is, neither test suite linked above makes it obvious how to do
> so.  That's what I'm looking for advice on.
>
> Alex Vincent
> Hayward, CA, U.S.A.
>
> [1] https://dxr.mozilla.org/mozilla-esr45/source/js/src/
> tests/ecma_6/Reflect
> [2] https://github.com/tc39/test262/tree/master/test/built-ins/Reflect
>
> --
> "The first step in confirming there is a bug in someone else's work is
> confirming there are no bugs in your own."
> -- Alexander J. Vincent, June 30, 2001
>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy handler.has() does not have a receiver argument?

2016-03-19 Thread Tom Van Cutsem
2016-03-19 0:15 GMT+01:00 Michael Theriot :

> To be clear, I'm not suggesting behavior like `getOwnPropertyNames` be
> overridden by anything on the prototype, just a way to use proxies without
> having to instantiate identical copies that all use the same handler.
>

If you can already reuse the same handler object between multiple proxies,
you're in good shape. There should be very little overhead in creating many
proxy objects that share the same handler. A proxy object is just an empty
object with a hidden reference to its handler.

Besides, if you want to reliably proxy multiple objects, you must
instantiate a proxy per object anyway, otherwise you may get in trouble
with object-identity. A single proxy object that proxies many different
target objects would have only 1 object identity, so all the proxied
targets would appear to be identity-equal.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Save Object.observe()! (please) + make WeakMap/WeakSet observable.

2015-11-05 Thread Tom Van Cutsem
2015-11-04 23:04 GMT+01:00 Matthew Robb <matthewwr...@gmail.com>:

>
> On Wed, Nov 4, 2015 at 4:46 PM, Tom Van Cutsem <tomvc...@gmail.com> wrote:
>
>> 1) If a module A hands out a reference to, say, a function f to modules B
>> and C, then C could use this primitive to replace f with its own proxied
>> version. Module B expects f to work as A intended, but module C can
>> completely override its behavior, stealing any arguments to the function
>> that B would pass. This is really bad behavior from a security and
>> modularity perspective.
>
>
> ​It seems like a straight forward solution for this might be adding
> something like `Proxy.preventTrapping(...)` and have this applied to all
> module exports/imports by default. Since modules work off bindings and not
> object properties.
>

We've thought about preventing certain objects from becoming trapped.
However, my explanation above only used modules to frame the discussion.
The security/modularity problem is in no way tied to module export/import
bindings only. Code can be modularised in ways other than using modules,
the most common one being multiple 

Re: Save Object.observe()! (please) + make WeakMap/WeakSet observable.

2015-11-04 Thread Tom Van Cutsem
2015-11-03 15:41 GMT+01:00 Matthew Robb :

> I probably have a terrible understanding of how this all works at a low
> level but I feel like a potential solution would be a method of "upgrading"
> a non-proxy object to be a proxy. The reason accessors are being used as
> they are now is because you can retro fit them. Maybe what I am suggesting
> is essentially like swapping out the internal pointer of an object with
> another object (such as the way live module bindings work). In this way you
> might upgrade an existing object to behave like a proxy.
>

This feature was proposed (under the name Proxy.startTrapping) back in
2011-2012. See <
https://web.archive.org/web/20140426153405/http://wiki.ecmascript.org/doku.php?id=strawman:direct_proxies#proxy.starttrapping_a.k.a._proxy.attach
>.

The two arguments that killed it, IIRC:

1) If a module A hands out a reference to, say, a function f to modules B
and C, then C could use this primitive to replace f with its own proxied
version. Module B expects f to work as A intended, but module C can
completely override its behavior, stealing any arguments to the function
that B would pass. This is really bad behavior from a security and
modularity perspective.

2) As Brendan mentioned, implementing this primitive requires a
Smalltalk-like "become:" that can swap object identities. This can be
really tricky or costly to implement (highly dependent on how objects are
represented in the VM).

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Save Object.observe()! (please) + make WeakMap/WeakSet observable.

2015-11-04 Thread Tom Van Cutsem
2015-11-04 0:22 GMT+01:00 Coroutines :

>
> With Object.observe() you get a global view of events generated by the
> target object, with Proxy you need to replace references to the target
> object with references to the Proxy.
>
> Now I'm changing my opinion again.  We need both.
>

I won't speak to whether we really need both, but your analysis that they
cater to different use cases is correct:

- O.o allows one to asynchronously observe (not intercept) operations on
another one's objects. This is safe.

- Proxies allow one to synchronously intercept operations on one's own
objects. This is safe.

- Proxies can obviously also be used to just observe one's own objects. As
an existence proof, I once did a simple O.o polyfill using proxies <
https://github.com/tvcutsem/harmony-reflect/blob/master/examples/observer.js>.
This is not generally useful though.

- Proxy.startTrapping would allow one to synchronously intercept operations
on another one's objects. This way lies madness. Don't go there.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Save Object.observe()! (please) + make WeakMap/WeakSet observable.

2015-11-03 Thread Tom Van Cutsem
2015-11-02 23:34 GMT+01:00 Coroutines :
>
> I come from Lua.  In Lua we make proxy objects with metamethods.  You
> create an empty table/object and define a metatable with a __index and
> __newindex to catch accesses and changes when a key/property doesn't
> exist.  I would primarily use this in sandboxes where I wanted to
> track the exact series of operations a user was performing to modify
> their environment (the one I'd stuck them in).


For this type of use case, you can use an ES6 Proxy <
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy>.
You can think of the proxy handler's methods as the 'metamethods' of the
proxy object.

What O.o would provide beyond Proxy is the ability to observe changes to
already pre-existing objects. However, since you mention you'd start with
an empty table/object, you should be able to create a fresh Proxy and use
that to trace all property accesses.

Proxies are particularly well-suited when you want to sandbox things, since
you should be in control of the sandboxed environment anyway and can set-up
proxies to intermediate. O.o is particularly well-suited to scenarios where
there are already plenty of pre-existing objects and you don't know ahead
of time which ones to observe and which not.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Calling toString on function proxy throws TypeError exception

2015-10-28 Thread Tom Van Cutsem
2015-10-27 12:47 GMT-04:00 Jordan Harband :

>
> Shouldn't tests in existing code that rely on `Function#toString` not
> throwing to indicate that something is callable, or throwing to indicate
> that it is not, remain true for a function proxy?
>

Excluding some host objects (as Boris pointed out), I think this does
capture the programmer's expectation in the common case.

When I wrote my Proxy shim for ES5 <
https://github.com/tvcutsem/harmony-reflect/>, I got feedback from
developers to patch F.p.toString() to please unwrap the proxy, as this
seemed to be the general expectation (just like Array.isArray should return
true for proxies-for-arrays).

I don't have a strong opinion on whether F.p.toString() should drill
through the proxy or just return "function() { [...] }", but would really
like it not to throw. A function proxy is, for all intents and purposes, a
valid function. Having F.p.toString report that it is called on an
"incompatible object" just feels wrong.

Even though just calling toString() would work fine on a membraned function
proxy, the idiom of storing built-in functions in variables and explicitly
.call()-ing those built-in functions is, to my understanding, still very
common.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Calling toString on function proxy throws TypeError exception

2015-10-23 Thread Tom Van Cutsem
2015-10-22 23:09 GMT+02:00 Allen Wirfs-Brock :

>
>
> Why would it be reasonable to do this for `toString`, but not also `call`,
> `apply`, and `bind`?  And ultimately this problem exists for all built-in
> methods that have have internal state dependencies. I just don’t see why we
> care so much specifically about `toString`
>

Calling Function.prototype.{call,apply,bind} on a function proxy should
obviously work (not throw a TypeError), as a function proxy has
well-defined behavior in such cases. For toString(), the two obvious
choices are to forward (show the function body of the target function), or
to generate a custom toString() representation like other exotic objects do
(e.g. "function () { [function proxy] }", or perhaps even show the
toString() representation of the apply trap).

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Calling toString on function proxy throws TypeError exception

2015-10-22 Thread Tom Van Cutsem
2015-10-22 21:03 GMT+02:00 Mark Miller :

> Ok, that all makes sense and is fine with me. Thanks for clarifying.
>
> Tom, I'm still curious what you remember?
>

What I remember is that the original direct proxies spec did the
transparent forwarding. wiki.ecmascript.org still seems to be down, but an
archived copy of late 2014 (thank you Wayback Machine) shows that the draft
spec indeed specified forwarding:

<
http://web.archive.org/web/20141214082226/http://wiki.ecmascript.org/doku.php?id=harmony:proxies_spec
>

*15.3.4.2 Function.prototype.toString ( O ) *

When called on a Proxy that is callable (i.e. whose target has a [[Call]]
internal method), returns the result of applying the built-in
Function.prototype.toString on the Proxy’s [[Target]]. Otherwise, throw the
same TypeError that would be thrown if this function is applied to a
non-function object.

For a revoked proxy, IsCallable is false so this operation throws a
TypeError.

I cannot recall any specific discussions on why that behavior was changed
to throwing a TypeError instead. The only reason I can come up with is that
it could be deemed a violation of the proxy's encapsulation in that it
should not leak such details about its target object.

I think it would be useful to at least reconsider the original forwarding
behavior. I think that in practice, forwarding toString() to the target is
not harmful, and the more places where code throws on a Proxy, the less
useful Proxies become altogether.

I noticed there is a stage 1 proposal to revise the specification of
F.p.toString() <
https://github.com/michaelficarra/Function-prototype-toString-revision>,
including standardizing its behavior for host objects. Perhaps the behavior
of F.p.toString() when applied to (function) proxies can become a part of
this revision effort?

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: await on synchronous functions

2015-08-05 Thread Tom Van Cutsem
2015-07-27 5:42 GMT+02:00 Dean Landolt d...@deanlandolt.com:


 On Sun, Jul 26, 2015 at 8:07 AM, Benjamin Gruenbaum benjami...@gmail.com
 wrote:

  Out of curiosity, can you give an example of the Not Good parts? ISTM
 the await prefix is more of an explicit cast than an implicit conversation,
 and other than the very small timing gap in how throws are handled I
 pointed out a few days ago, I can't think of any situations where a throw
 would make more sense than casting values to promises.

 Sure, lots of such cases exist today with promises and are easy to
 reproduce

 ```js
 async function foo {
 let result = await bar; // instead of bar();
 let result2 = await callbackFn(); // await on function that was not
 promisified yet, that is, it takes a callback
 let result3 = await [p1, p2, p3]; // people might expect a
 Promise.all on an array, but this doesn't actually wait for anything.
 }
 ```


 The first example is a basic type error, not at all specific to promises
 or async programming -- it could be made any number of ways. If you want to
 call it a footgun, that's fine -- but ISTM the only real solution is use
 TypeScript (or some analog).

 I don't see how the last example could possibly exist today as it reflects
 a hypothetical user's misunderstanding of `async/await` syntax
 specifically. Perhaps there's a case to be made that there's a footgun here
 (though I'd disagree), but it's beside the point of this thread.


I recently found out that a popular async cflow library for node based on
generators, co https://github.com/tj/co does allow one to await (yield)
an array, with the semantics that Benjamin alluded to (Promise.all
synchronization). At least it indicates that this is not a totally
unrealistic expectation on behalf of users. Personally I think
automatically Promise.all'ing arrays is a bit too implicit, but I can
understand why people find it appealing.


 But the second example, `await callbackFn()`, seems reasonable. I still
 think it would be a shame to punt on otherwise elegant ergonomics just due
 to this, but I buy that there's at least some benefit now.


Speaking from experience with a programming language I was involved with
called AmbientTalk, which has JS-style Promises, we did run into this issue
and we had a pragmatic way of solving it. Translated into the context of
this discussion, what we specified is that `await undefined` would raise a
runtime error, while `await any-non-promise-value` would coerce the
non-promise value into a resolved promise and await that promise instead.

At first sight, it might feel awkward for `await` to special-case
`undefined`, but given that it is JS's implicit return value, I suspect it
would catch a lot of errors of the type Benjamin described above. It's a
pragmatic way of dodging the footgun without completely breaking the
symmetry between await and Promise.resolve.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: await on synchronous functions

2015-07-17 Thread Tom Van Cutsem
2015-07-17 19:41 GMT+02:00 Andrea Giammarchi andrea.giammar...@gmail.com:

 If I might, if there's one thing that has never particularly shone in JS,
 that is consistency.

 I see only two possibilities here: 1) it throws with non Promises 2) it
 Promisify anything that's not a Promise as if it was a
 `Promise.resolve(1)` ... but since there's too much magic in the second
 point, I'd rather stick with the first one.


I would be highly in favor of (2). Think about a large program where you
refactor a single async function to no longer be async. Then I see no
reason why I should be forced to refactor all of its callers to remove the
await keyword. Going from sync to async requires refactoring because you're
introducing new potential interleaving hazards, but any code that is
already prepared to work with async functions (or promises in general)
should work equally fine on immediately resolved promises.

regards,
Tom




 Just my quick thoughts

 Best Regards

 On Fri, Jul 17, 2015 at 6:33 PM, Kevin Smith zenpars...@gmail.com wrote:

 I know the spec for this isn't finalized, but what is the current
 direction for the behaviour when await is used on a function that is not
 marked async and doesn't return a Promise? Should it run immediately or
 wait for the next turn of the event loop?


 More generally, the question is: what should await do for non-promises?

 await 1;

 Should it force a job to be queued?

 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss



 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: ES6 Proxy Function Call Trap

2015-06-11 Thread Tom Van Cutsem
Edwin,

I sympathize with your point-of-view, but we've debated all the pros and
cons of `invoke` long ago, and unless new arguments are brought to the
table, I don't think it will be added again soon.

To clarify why the invoke = get + call equivalence is so important,
consider for instance the common coding pattern of a conditional method
call, where one only wants to invoke a method if it exists:

```js
var foo = obj.foo;
if (foo) {
  foo.call(obj)
}
```

With the current Proxy API, the `get` trap returns a function (or a proxy
for a function), and the code works fine regardless of whether foo() is
called as a method, or as a function.

With the addition of `invoke`, if you don't also provide a `get` trap, then
the code will not behave as expected. Likely `obj.foo` will return
`undefined`, even though `obj.foo()` would have triggered the `invoke` trap
and done something useful.

So, *any* robust use of `invoke` still requires implementing a `get` trap
(to allow for all the use cases where methods are extracted as functions
from objects). As a result, it would lead to a net *increase* in
lines-of-code.

2015-06-11 15:48 GMT+02:00 Kevin Smith zenpars...@gmail.com:

 Could a userland library make writing these kinds of proxies more
 ergonomic?


I don't see why not. The Proxy API offers only the bare minimum tools to
create your own custom exotic objects. Arguably we need to grow some good
libraries around it to make building these types of objects more routine
(although I'd be the first to point out that you should avoid exotic
objects unless there's a really compelling reason to go that route)

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Maybe we need a reflect API to iterate over instance members

2015-06-02 Thread Tom Van Cutsem
2015-06-01 20:36 GMT+02:00 Alexander Jones a...@weej.com:


 On Monday, June 1, 2015, Tom Van Cutsem tomvc...@gmail.com wrote:


 Or since Proxy traps correspond 1-to-1 to the internal methods in the
 spec, the primary goal of the Reflect API was to expose the essential
 methods that make up Javascript's object model as defined by the spec.


 I like this definition. Is it written down? (I need ammunition for
 Reflect.type(x)!)


There's some rationale on the original wiki page for the reflect API: 
http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api#purpose.

We also had a related short debate on this list 3 months ago, see 
https://esdiscuss.org/topic/reflect-getownpropertysymbols#content-0, in
particular, Allen's comment: In ES6, the primary role of the Reflect
object is to provide direct access to an object's essential internal
methods.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Maybe we need a reflect API to iterate over instance members

2015-06-01 Thread Tom Van Cutsem
2015-06-01 8:38 GMT+02:00 Domenic Denicola d...@domenic.me:

 From: es-discuss [mailto:es-discuss-boun...@mozilla.org] On Behalf Of
 Gray Zhang

  I’m just wondering is there any reason that Reflect API is not suitable
 to provide such functionality?

 Reflect currently contains only methods which correspond to proxy traps.
 There has been talk of extending it beyond that, but making that first step
 is going to be a hurdle for whoever’s proposing it to extend it.


Or since Proxy traps correspond 1-to-1 to the internal methods in the
spec, the primary goal of the Reflect API was to expose the essential
methods that make up Javascript's object model as defined by the spec.
There are many utility methods one may want to add on top, but it seems
better to wait and see what the community comes up with rather than to try
to codify an extensive API before it has seen any significant use.

Regarding duplicates: ES6 has Sets. It should be fairly straightforward to
adapt the above example to de-dup inherited property names.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Subclassing ES6 objects with ES5 syntax.

2015-04-28 Thread Tom Van Cutsem
2015-04-28 5:01 GMT+02:00 Kevin Smith zenpars...@gmail.com:

 Looking over the Reflect namespace, I also see that Reflect.get and
 Reflect.set have been given powers not expressible with syntax:  the
 receiver does not have to be a prototype parent of the target.


Did you mean the receiver does not have to be a prototype [child] of the
target? I would expect that to be the common case. Anyway, with __proto__
/ setPrototypeOf as part of the language, two objects being in a
parent-child prototype relationship is not an invariant you can always
count on. Additionally, if the property is an accessor, the receiver
argument is passed as the `this` binding into the accessor. But it's easy
enough to call getOwnPropertyDescriptor, extract the getter or setter, and
`call` it with a this-binding that also isn't in a prototype relation with
the object holding the accessor. So, for Reflect.{get|set} at least, I
don't see an issue.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: super.prop assignment can silently overwrite non-writable properties

2015-04-22 Thread Tom Van Cutsem
2015-04-21 22:15 GMT+02:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 Yes, I considered that possibility in deciding upon the proposed change.
 The reason I error out if the Receiver property is an accessor is because I
 think the most likely way this scenario will occur is when that that access
 includes a `super.prop` assignment.  That would result in an infinite
 [[Set]] recursion.  For example:

 ```
 var y = {
  __proto__: x,
  set prop(v) {
  // ...
  super.prop = v;
  }
 };
 y.prop = 42;
 ```


Assuming `x` here is the object where prop is bound to an accessor, can
you clarify how this would lead to an infinite recursion?

y.prop = 42; // 9.1.9 step 2 binds ownDesc to y's accessor, and calls it in
step 9
super.prop = v; // 9.1.9 step 2 binds ownDesc to x's accessor, and calls it
in step 9
x's setter then runs `v = n;` and the assignment terminates

I must be missing something?
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: super.prop assignment can silently overwrite non-writable properties

2015-04-22 Thread Tom Van Cutsem
2015-04-21 21:52 GMT+02:00 Kevin Smith zenpars...@gmail.com:

 Another interpretation might be that since you've explicitly stated an
 intention to bypass the receiver's setter, falling back to that setter
 would be a bug.


No, that wouldn't be right. To clarify, Reflect.set takes the following
params: Reflect.set(lookupObject, propertyName, propertyValue,
receiverObject)

It states that we want to start the lookup of propertyName in lookupObject,
but eventually, the object to be updated is receiverObject. The reason for
the split between lookupObject and receiverObject is so that Reflect.set
(or the [[Set]] internal method, which mirrors it) can encode a prototype
chain walk. For a regular property assignment, we always start at the
receiverObject, that is, we initially call:

Reflect.set(receiverObject, propertyName, propertyValue, receiverObject)

As long as we don't find propertyName, we recurse:

Reflect.set(receiverObject.__proto__, propertyName, propertyValue,
receiverObject)
Reflect.set(receiverObject.__proto__.__proto__, propertyName,
propertyValue, receiverObject)
...
and so on until we hit the root.

The only reason why [[Set]] wants to climb the prototype chain in this way
is to see if there are non-writable inherited properties. However, if the
receiverObject has overridden that property (either with an accessor or a
writable property), then the inherited property takes precedence.

In normal ES5 code, since lookup is guaranteed to start at receiverObject,
this precedence is implicitly guaranteed. In ES6, with both `super.prop`
syntax and Reflect.set, the programmer can explicitly start the lookup
higher up the prototype chain. The implicit precedence of the
receiverObject's property is now no longer guaranteed, because we've
skipped looking for the property in receiverObject first.

That's why I think in step 5.c and onward, we must now explicitly ensure
that existingDescriptor takes precedence over the newly defined descriptor.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: super.prop assignment can silently overwrite non-writable properties

2015-04-21 Thread Tom Van Cutsem
FWIW, you can reproduce this test case without reference to the new `super`
syntax:

```
var parent = {};
var x = Object.create(parent, {
  prop: { value: 1, configurable: true, writable: false }
});

Reflect.set(parent, prop, 2, x); // expected false, but under current
semantics will return true
```

However, I'm not sure the new step 5.e.i. is correct: why abort the [[Set]]
when the existing descriptor is an accessor? If it has a setter, it seems
to me the setter should be run. Testcase:

```
var parent = {};
var v = 1;
var x = Object.create(parent, {
  prop: { get: function() { return v; }, set: function(n) { v = n; },
configurable: true }
});

Reflect.set(parent, prop, 2, x); // under Allen's proposed changes, this
will return false while I think it should just call the setter?

(You don't end up in 9.1.9 step 7 in the above case, because 4.d.i first
sets ownDesc to a data descriptor. This falls into step 5. In step 5.c. the
existingDescriptor will be the accessor. The new step 5.e.i then returns
false rather than checking whether existingDescriptor.[[Set]] is callable)

Cheers,
Tom

2015-04-21 5:25 GMT+02:00 Kevin Smith zenpars...@gmail.com:

 5.e If *existingDescriptor* is not *undefined*, then
i.   If IsAccessorDescriptor(*existingDescriptor*), return *false*
 .
ii.  If *existingDescriptor*.[[Writable]] is *false*, return
 *false*.
iii.  Let *valueDesc* be the PropertyDescriptor{[[Value]]: *V*}.
iv.  Return *Receiver*.[[DefineOwnProperty]](*P*, *valueDesc*).

 Lines 5.e.i and 5.e.ii are new additions.


 Looks good to me.

 Thanks, Jason, for bringing this up!

 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Reflect.getOwnPropertySymbols?

2015-03-18 Thread Tom Van Cutsem
2015-03-16 17:53 GMT+01:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 It's possible, that in the future derived reflective operations such as
 those might be added to Reflect.*.

 There are a couple of design questions to consider for future extensions:

 1) Is there any benefit to duplicating to having the same function that
 exists on both Object.* and Reflect.*


Note that not all methods we defined on Reflect.* were mere duplicates of
their Object.* counterparts. Some had different return values. For
instance, Object.freeze(obj) always returns obj or throws, while
Reflect.freeze(obj) was specced to return a simple boolean value indicating
success or failure.

That said, I think we made the right call to limit Reflect.* to just the
essential internal methods in ES6.

cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: @@toStringTag spoofing for null and undefined

2015-01-21 Thread Tom Van Cutsem
2015-01-21 0:01 GMT+01:00 Mark S. Miller erig...@google.com:

 What I think I remember hearing from Tom is that Dave's main point, and
 the main argument with Tom, was precisely allowing proxies to intercede on
 === checks, in which case you wouldn't even have that as a reliable
 indicator.


This is also how I remember it.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: @@toStringTag spoofing for null and undefined

2015-01-21 Thread Tom Van Cutsem
Hi Dave,


 On Tue, Jan 20, 2015 at 4:44 PM, David Ungar un...@mac.com wrote:

 Self stratifies things into base- and meta- level. The idea is that
 almost all code is better off sticking to base level because that promotes
 encapsulation and reuse.
 At base-level all you can do is throw messages at objects and then throw
 more messages at whatever bounces off of what the first messages return.
 So you can always substitute an object with similar behavior for another.

 At meta-level, you can interrogate the object to look inside; what slots
 it has, etc.


I subscribe to this design point-of-view (AmbientTalk followed much the
same design, in Self and Smalltalk's footsteps).

I also find your observation about moving identity to the meta-level (and
thus to a more expert part of the language) revealing. As long as the
majority of regular application code uses polymorphic equality, you're good.

Ideally, we would have had '==' be an overridable operator, allowing
objects to re-implement identity how they see fit. And we would have had a
more obscure, but unspoofable identity test (in the form of a method call
like Object.is or Object.equals). But alas, that is not JS reality.

The trouble with '===' being our reliable identity test is that it is still
very convenient syntax, so developers will tend to use it even if they
would have been comfortable with a polymorphic, extensible '==' test. And
of course, many in our community have for a long time advocated not using
'==' because it performs implicit conversions.

It's worth comparing JavaScript's situation to Java's: Java has '==' as a
reliable identity test, and it has the equals() method inherited from
java.lang.Object as the polymorphic test. Even in Java though, you often
hear programmers complain about not being able to redefine '==' when they
start to proxy certain objects. My hypothesis is that this is because '=='
is again too convenient syntax, leading developers to over-use it.

Now, coming back to equals(): if only we as a community could agree to a
standard duck-typed method name to perform object equality checks, we
wouldn't need to change the base language at all. We don't need a static
java.lang.Object.equals() method, we can just use duck-typing. The trouble
with that is of course that if the language doesn't choose a standard name,
the community will invent their own. And indeed, many JavaScript libraries
define their own equality operators of sorts (some do double-dispatch, some
do shallow structural comparisons, some do deep-equality, etc.)

So, just like Promises/A+ 'standardised' on 'then' to do promise chaining,
maybe we need to rally around and promote an extensible equality test
implemented as a plain common method. No fancy new syntax or language
extensions required. Of course, we'd still be left with legacy code that
will continue to use '==' and '==='.


 From your response, it sounds as if == is non-overidable today. Is that
 right?


As Brendan and Mark already pointed out, '==' is indeed non-overridable
today. I'm hopeful that Brendan's value types proposal will amend that in
the future. Barring community consensus on an equals() duck-typed protocol
(which is unlikely to happen), I think that's our best bet in recovering
the benefits of extensible equality tests while keeping nice syntax.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Add Reflect.isConstructor and Reflect.isCallable?

2014-12-21 Thread Tom Van Cutsem
Adding Reflect.{isCallable, isConstructor} looks reasonable to me. If the
spec needs these internally, chances are JS developers will need them at
one point. And as you note, typeof === function is a common work-around
in use today. So +1.

2014-12-21 0:20 GMT+01:00 Tom Schuster t...@schuster.me:

 Thank you both.
 Looking forward to the feedback.

 On Fri, Dec 19, 2014 at 6:55 PM, Rick Waldron waldron.r...@gmail.com
 wrote:

 Done: https://github.com/tc39/agendas/blob/master/2015/01.md

 On Fri Dec 19 2014 at 12:26:33 PM Jason Orendorff 
 jason.orendo...@gmail.com wrote:

 Having said that, I do think Reflect.isCallable and isConstructor
 would be a fine addition to ES7. These places where we check if an
 internal method exists feel like a sort of secret-handshake part of
 the MOP; we should expose them.

 Any objections?

 Would someone please add it to the agenda for the next meeting?

 -j
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss



 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[DefineOwnProperty]] (P, Desc)

2014-11-30 Thread Tom Van Cutsem
2014-11-27 12:05 GMT+01:00 Axel Rauschmayer a...@rauschma.de:


 https://people.mozilla.org/~jorendorff/es6-draft.html#sec-proxy-object-internal-methods-and-internal-slots-defineownproperty-p-desc

 Quote (note typo in second item):

 1. A property cannot be added as or modified to be non-configurable, if it
 does not exists as a non-configurable own property of the target object.

 2. A property may not be non-configurable, if is corresponding
 configurable property of the target object exists.

 Question: Doesn’t #1 imply #2?


Hmm, I think you're right. It seems to me that #2 is more an invariant of
[[GetOwnProperty]] than of [[DefineOwnProperty]]. Perhaps it's just a
copy-paste remnant. Allen, can you clarify what you had in mind?
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Is `List` really a specification type?

2014-11-30 Thread Tom Van Cutsem
2014-11-27 17:12 GMT+01:00 Claude Pache claude.pa...@gmail.com:

 Lists are indeed specification-only types, and the result of the
 `[[OwnPropertyKeys]]` internal method call is never directly observed by
 the programmer: it is only used as an intermediate result within
 algorithms. A List is, I presume, a finite ordered sequence of values.


Indeed, user-facing functions convert the List to an Array, see e.g.
Reflect.ownKeys:
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect.ownkeys

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: 9.5.8 [[Get]] (P, Receiver)

2014-11-30 Thread Tom Van Cutsem
2014-11-27 12:32 GMT+01:00 Axel Rauschmayer a...@rauschma.de:

 Suggestion: mention in both cases that the property is an own property of
 the target.


+1. It doesn't hurt to be too explicit in stating these invariants.

It may help Allen if you can repost this as a bug in the ecmascript bug
tracker: 
https://bugs.ecmascript.org/enter_bug.cgi?product=Draft%20for%206th%20Edition


Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-17 Thread Tom Van Cutsem
2014-11-17 18:30 GMT+01:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 But probing through the proxy as has been proposed is a terrible violation
 of the MOP API boundary and isn't generalizable to other built-ins that are
 dependent upon internal state. While a null handler proxy on a direct
 instance of Array would work under that design, a comparable Map.isMap or
 Promise.isPromise method would not.  Rather than a one-off hack I think we
 should use a new pattern that is generalizable:


If we can find consensus on this much more general pattern of type-testing
by using a symbol on the constructor, I'm all for it. +1!
I also think we don't want to special-case Proxies in the proposed
type-testing algorithm.

That said, if we cannot come to a consensus on this more generic form of
type-testing, I would still defend the position that Array.isArray merits
an exception (compared to Map.isMap/Promise.isPromise etc.) *precisely
because* Arrays were carefully defined not to depend on any special
instance state. In this scenario, repurposing the @@isConcatSpreadable
symbol seems like the most obvious thing to do (it currently feels terribly
ad-hoc, making it something more generic such as @@isArrayLike makes more
sense to me)

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-16 Thread Tom Van Cutsem
2014-11-17 3:34 GMT+01:00 Frankie Bagnardi f.bagna...@gmail.com:

 Consider when Array.isArray would be used.  In my experience, checks to
 see if something is an array are used for:

  - deciding how to iterate it (for(;;) vs for..in, for example)


This is a good one. Here, again, a typical proxy-for-array would work as
intended, as the for(;;) loop just queries .length and properties named
0, 1, ... via standard [[Get]] access.

Can someone come up with a convincing example where a proxy-for-array would
*not* work as intended?
(convincing here means it doesn't involve a proxy that blatantly violates
the Array contract on purpose)

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Tom Van Cutsem
2014-11-14 21:00 GMT+01:00 Allen Wirfs-Brock al...@wirfs-brock.com:

 On Nov 14, 2014, at 11:41 AM, Domenic Denicola wrote:

  Yeah, more or less. A realm-independent instanceof. This makes sense
 also from the historical perspective that `Array.isArray` was meant to
 provide a cross-realm alternative to `instanceof Array`. (I believe that
 was the case; before my time.)

 No really, it was a way to expose a test of the [[Class]] internal
 property.  That test wasn't dependent upon the [[Prototype]] chain.


I think what Domenic was saying is that Array.isArray used such a test
*because* instanceof Array didn't work reliably cross-realms. I too vaguely
recollect that reliable cross-realm instanceof Array testing was a
primary motivation for Array.isArray.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Tom Van Cutsem
2014-11-13 22:35 GMT+01:00 Tom Van Cutsem tomvc...@gmail.com:

 My intuition is that Array.isArray is often used to branch based on
 whether code received just one versus a collection of values. E.g. a
 function may take a single parameter that can be bound to either a single
 value or a collection of values, and treat a collection of values
 differently. In fact, that is essentially what Array.prototype.concat does:
 if the argument is an array, splice its values, otherwise, don't splice.
 This has nothing to do with `length` magic. The same goes for
 JSON.stringify (serialize as [] vs {}).


Amusingly, not only does JSON.stringify(value, replacer, space) branch on
the type of its `value` argument (to serialize as [] vs {}), it
apparently also type-tests its `replacer` argument, which can either be a
function or an array. If it's an array, it serves as a whitelist of the
properties that can appear in the output. While it's unlikely anyone would
ever want to pass a proxy-for-array as a JSON whitelist, JSON.stringify is
an example of the kind of type-testing I had in mind to simply distinguish
whether one of its parameters is just one value vs. a collection of values.
For such functions, there would be no harm in treating proxies-for-arrays
as arrays.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Tom Van Cutsem
2014-11-14 21:52 GMT+01:00 Jeremy Martin jmar...@gmail.com:

 Allen's previous comments:

 Proxies are not transparent forwarders!  In particular their default
 handling of the `this` value on method invokes will break any built-in
 method that needs to access internal slots of an object.


 ...lead me to believe that this isn't the case for proxified Arrays, so
 I'd have to reverse my earlier position, as `Array.isArray(proxifiedArray)`
 evaluating to true just seems likely to break code.


For the particular case of Arrays though, because Array methods were
carefully specified to be generic (i.e. to also work on non-array objects),
they will work just fine on proxies-for-arrays:

var p = new Proxy([1,2,3] , {} );
var a = p.map(function(x) { return x + 1; });
console.log(a); // [2,3,4]

So, of all the exotic objects in the ES and WebIDL specs, Arrays are
probably one of the few exceptions where a Proxy wrapper *is* transparent
by default.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Tom Van Cutsem
2014-11-13 20:31 GMT+01:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 3) Proxies. Should Array.isArray treat proxy instances specially? To
 answer this question we need to think about what a ES programmer actually
 thinks Array.isArray means? The meaning that ES5 established is that
 Array.isArray returning true means that the object observably maintains the
 array `length` invariant.


Is the `length` invariant really the dominant meaning JS developers
attribute to Array.isArray? I think to most developers Array.isArray(obj)
returning true means that it's safe to call the array utilities (map,
forEach, ...) on obj, not so much that obj.length is special.

My intuition is that Array.isArray is often used to branch based on whether
code received just one versus a collection of values. E.g. a function may
take a single parameter that can be bound to either a single value or a
collection of values, and treat a collection of values differently. In
fact, that is essentially what Array.prototype.concat does: if the argument
is an array, splice its values, otherwise, don't splice. This has nothing
to do with `length` magic. The same goes for JSON.stringify (serialize as
[] vs {}).

Now, if we take the meaning of Array.isArray to be supports the
Array.prototype utility methods, a proxy-for-array may of course expose a
totally different API, leading a client that expects to be able to use the
Array.prototype methods to fail. But this foregoes the fact that for
virtually all practical use cases of proxies, proxy authors will not do
this. They want to be able to wrap objects, intercept some things, but
mostly faithfully forward those operations to the wrapped target. It would
be rare for a proxy to change the API of the thing it wraps. Indeed, the
whole point of proxies is to be able to intercept operations without
modifying client code.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
I agree with your sentiment. I have previously advocated that Array.isArray
should be transparent for proxies. My harmony-reflect shim explicitly
differs from the spec on this point because people using the shim
spontaneously reported this as the expected behaviour and thought it was a
bug that Array.isArray didn't work transparently on proxies.

As far as I can remember, the argument against making Array.isArray
transparent is that it's ad hoc and doesn't generalize to other types /
type tests. My opinion is that array testing is fundamental to core JS and
is worth the exception.

Regards,
Tom

2014-11-12 17:04 GMT+01:00 Axel Rauschmayer a...@rauschma.de:

 The subject is a SpiderMonkey bug.

 Is that really desirable? Doesn’t it invalidate the Proxy’s role as an
 interceptor?

 --
 Dr. Axel Rauschmayer
 a...@rauschma.de
 rauschma.de




 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 19:53 GMT+01:00 Rick Waldron waldron.r...@gmail.com:

 I agree and I want to know if you think this is worth revisiting once
 more? Next meeting's agenda?


I don't think we've ever discussed this issue before during a TC39 meeting
(but I didn't attend quite a few, so I may be wrong). Adding it to the
agenda for next meeting seems good to me.

regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 20:37 GMT+01:00 Kevin Smith zenpars...@gmail.com:

 In general, it appears that SM unwraps proxies so that internal slot
 access is transparently forwarded.  I don't see any such unwrapping in the
 ES spec though.  I assume that the spec is correct?


This auto-unwrapping for internal slots used to be part of an early
iteration of direct proxies 
http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies#wrapping_irregular_objects
but was not carried over into the ES6 spec. IIRC, mainly because just
forwarding any internal slot access endangers the encapsulation properties
of membrane-like use cases.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 23:49 GMT+01:00 Andrea Giammarchi andrea.giammar...@gmail.com:

 If Array.isArray should fail for non pure Arrays, can we have a
 Proxy.isProxy that never fails with proxies ?


We ruled out `Proxy.isProxy` very early on in the design. It's antithetical
to the desire of keeping proxies transparent. In general, we want to
discourage type checks like you just wrote.

If you're getting handed an object you don't trust and need very strong
guarantees on its behavior, you'll need to make a copy. This is true
regardless of proxies. In your example, even if the array is genuine, there
may be some pointer alias to the array that can change the array at a later
time.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 20:53 GMT+01:00 Rick Waldron waldron.r...@gmail.com:


 Done https://github.com/tc39/agendas/blob/master/2014/11.md


Thanks. A related point: my harmony-reflect shim also patches
Array.prototype.concat such that it recognizes proxies-for-arrays and will
splice their elements (rather than adding the proxy as a single element to
the target array).

In ES6, this may not be necessary since a proxy could implement
@@isConcatSpreadable (see 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.concat
step 9.b)

However, looking at IsConcatSpreadable 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-isconcatspreadable
step 5, you'll notice it explicitly tests for Arrays. *If* we decide that
Array.isArray should return `true` for proxies-for-arrays, *then* I think
we should relax this step 5 to also return `true` for proxies-for-arrays,
on the grounds of consistency and principle-of-least-surprise.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-13 8:18 GMT+01:00 Andreas Rossberg rossb...@google.com:

 On 12 November 2014 17:23, Tom Van Cutsem tomvc...@gmail.com wrote:
  My opinion is that array testing is fundamental to core JS and is
  worth the exception.

 This change would only make sense if we also were to special-case all
 other places in the spec that currently say if O is an exotic Array
 object, ... to magically handle proxies. Otherwise, all you get is a
 predicate that gives a misleading result.


Yes, good point. See my just-recent post on Array.prototype.concat.


 However, I don't think we want to special-case all those places. That
 would put us on a very slippery slope.


A cursory look at the spec reveals the following built-ins that test for
exotic Arrays:

- Array.isArray
- Array.prototype.concat
- Array.prototype.filter
- Array.prototype.map
- Array.prototype.slice
- Array.prototype.splice
- JSON.parse
- JSON.stringify
- Object.prototype.toString

filter, map, slice and splice didn't used to test for arrays in ES5. They
seem to test for arrays such that the new array they create derives from
the same realm. This can probably be made to work with proxies-for-arrays,
but I'm not sure it is necessary or desirable.

For JSON.stringify, the question is whether a proxy-for-array should
serialize as [] vs {}. Obviously, if Array.isArray(proxyForArray), I
would expect it to serialize as [].

For toString, proxies could still implement @@toStringTag to be able to
intercept that call. At this point, I believe
Object.prototype.toString.call(proxyForArray) would return [object
Object].

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Spec bug (proxies)? 9.5.8 [[Get]] (P, Receiver)

2014-11-03 Thread Tom Van Cutsem
2014-11-02 22:10 GMT+01:00 Axel Rauschmayer a...@rauschma.de:

 OK. It surprised me, because `get` is so much about inheritance chains.

 I’ve not seen a rationale for the proxy invariants anywhere (including
 your technical report on proxies). Can I read up on it somewhere?


Do you mean the rationale for looking only at own properties, or more
generally the rationale behind invariant checking in proxies? If the
latter, then the best rationale is written up in our ECOOP13 paper Trustworthy
proxies: virtualising objects with invariants
http://research.google.com/pubs/pub40736.html. If the former, this is
kind of self-evident when looking at the invariants already described in
ES5 (in particular, section 8.6.2
http://ecma-international.org/ecma-262/5.1/#sec-8.6.2).
Non-configurability and non-extensibility never involve the prototype
chain. They only apply to individual own properties or individual objects,
never to prototype chains of objects.


 In general, the proxy parts of the spec are very readable. Especially the
 summary of the invariants in each section on internal proxy properties is
 helpful.


Thanks! (credit also goes to AllenWB and MarkM for refining those
invariants)

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Spec bug (proxies)? 9.5.8 [[Get]] (P, Receiver)

2014-11-02 Thread Tom Van Cutsem
No, the proxy invariant checking mechanism never looks at inherited
properties. Invariants related to frozenness (non-configurable,
non-extensible) relate only to own properties. For example, even if an
object is frozen, it may still inherit from a non-frozen object whose
interface may change. And then there's `setPrototypeOf`, which may cause
inherited properties to change altogether.

Cheers,
Tom

2014-11-02 19:25 GMT+01:00 Axel Rauschmayer a...@rauschma.de:


 https://people.mozilla.org/~jorendorff/es6-draft.html#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver

 To enforce the invariants, this operation uses `targetDesc`. That property
 descriptor is retrieved via target.[[GetOwnProperty]], which ignores
 inherited properties. Shouldn’t inherited properties be taken into
 consideration, too?

 --
 Dr. Axel Rauschmayer
 a...@rauschma.de
 rauschma.de




 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proposal: Abstract References

2014-10-27 Thread Tom Van Cutsem
2014-10-27 15:00 GMT+01:00 Andreas Rossberg rossb...@google.com:

  but without breaking membrane transparency.

 I'm still not sure I understand how this affects membranes
 specifically. A membrane would never pass a proxied object to a
 non-proxied function from the same side. So functions accessing (or
 testing for) private state on an object are a non-issue in that
 scenario, because this access never crosses the membrane, does it?
 After all, membranes work just fine with builtins or host objects
 (otherwise they would be useless).


I believe what Mark was referring to is the fact that if a WeakMap crosses
the membrane, it gets proxied. Manipulating the WeakMap using
WeakMap.prototype.{get,set} subsequently allows the membrane to intercept
and wrap those operations.

With (private) symbols, we couldn't come up with a satisfactory way to
combine them with membranes. Treating the symbol as data and passing it
straight through the membrane creates an obvious leak. Treating it as an
opaque identity and proxying that identity results in a useless proxied
identity on the other side of the membrane. W.r.t. membranes, the key point
of using WeakMaps for private state is that the membrane can properly
intercept the 'get' and 'set' operations.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Making operations on property descriptors more robust against Object.prototype hazards

2014-09-13 Thread Tom Van Cutsem
2014-09-13 17:49 GMT+02:00 Brendan Eich bren...@mozilla.org:

 It's not nice to lose .toString, though.

 Tom, didn't you have an idea for a fix? I can't find it but vaguely recall
 it (or dreamt it!).


No, not that I know of. As highlighted in the old thread linked to by
Claude, there is a legitimate use for considering inherited attributes:
inheriting defaults. Brandon Benvie stepped in to acknowledge he actually
used this pattern.

Of course, in the old thread we were talking about Object.{dP, gOPD} which
we can't change because of backwards-compat issues. Claude is suggesting we
can still change Reflect.{dP, gOPD} in this regard. I'm hesitant to do so
though, because I feel the root cause of the problem is the monkey-patching
of Object.prototype, rather than property descriptors being badly
designed just because they consider inherited attributes. Even if we would
fix this particular part of the Reflect API, code that does
`Object.prototype.get = ...` is likely to cause other bugs as well.

Speaking about that particular example: if one adds `Object.prototype.get =
function(){}`, then trying to define a data descriptor will immediately
fail noisily because the spec explicitly checks that a descriptor can't be
both a data and accessor property at the same time, so this particular
conflict is likely to be detected very soon.

Cheers,
Tom








 /be


 Claude Pache wrote:

 Hi,

 As noted some time ago, there is an issue with `Object.defineProperty`
 when it happens that someone has the facetious idea to give some value to
 `Object.prototype.get` [1].

 While it is hardly an issue in day-to-day programming, I think that it is
 a good idea to make sure that specialized API (Reflect, proxy traps) are
 robust by design against that bug^H^H^H feature. Concretely, I propose:

 (1) proxy.[[DefineOwnProperty]] — When a proxy defines the corresponding
 trap, it shall receive an object with no prototype as property descriptor.

 (2) Reflect.getOwnPropertyDescriptor —That method shall return an object
 with no prototype, so that it can be readily used elsewhere, e.g. in
 Reflect.defineProperty.


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Does async/await solve a real problem?

2014-09-12 Thread Tom Van Cutsem
2014-09-11 16:22 GMT+02:00 Florian Bösch pya...@gmail.com:

 A - B - C - D - E changes to

 A - B - C - D - async E and causes

 A await - B await - C await - D await - async E

 And of course if A, B, C or D is used anywhere else it percolates trough
 the entire call graph.

 Trying to protect people from interlaved code execution effects is noble.
 But doing so by introducing a rote thing to type everytime you change the
 code somewhere underneath is wrong. It's wrong because it breaks logic
 isolation, it becomes impossible to change part of the library/utiity code
 without this change affecting all code that uses it. This guarantees that
 it doesn't happen in practice, because it's too painful to do. It requires
 the code, that uses other code, to know about the internal behavior of that
 code.


Arguably, the fact that a function may suspend in mid-flight should be part
of its documentation (i.e. function signature), as it directly affects the
caller.

As an analogy, consider `IO` in Haskell: if you have this large piece of
purely functional code, and deep down you're all of a sudden introducing
mutable state, you will need to refactor the larger piece of code to reveal
that it in fact performs IO as well.

While this refactoring may be tedious (no disagreement there), it forces
you to review all affected code, which is good, because the dependencies of
that code may have changed (i.e. side-effect the client previously thought
would execute atomically may now no longer be atomic).

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Violations of internal method invariants?

2014-07-31 Thread Tom Van Cutsem
2014-07-31 15:43 GMT+02:00 Jason Orendorff jason.orendo...@gmail.com:

 Right Thing: I think [[PreventExtensions]] on these objects should
 always return false. I think [[DefineProperty]] on these objects
 should return false if Desc.[[Configurable]] is false or if it's
 missing and would default to false. That'll cause Object.freeze(form)
 and Object.defineProperty(form, x, {configurable: false}) to throw a
 TypeError. Seems legit.


+1. They key point is that [[DefineOwnProperty]] should not try to coerce
configurable:false to configurable:true. It should just reject such
property updates.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Violations of internal method invariants?

2014-07-31 Thread Tom Van Cutsem
2014-07-31 15:26 GMT+02:00 Jason Orendorff jason.orendo...@gmail.com:

 There's not a rule that says flat-out, If Desc.[[Configurable]] is
 false and [[DefineOwnProperty]](P, Desc) returns true, that counts as
 'observing' the property P as a non-configurable property on the
 target. but if you take that as read, what WebIDL is doing here is
 banned.

 Note that steps 14-22 of 9.5.6 (Proxy#[[DefineOwnProperty]]) do some
 checks which enforce this rule.

 http://people.mozilla.org/~jorendorff/es6-draft.html#sec-proxy-object-internal-methods-and-internal-slots-defineownproperty-p-desc

 Tom, can the prose be improved? What's the intent?


The intent is indeed that if [[DefineOwnProperty]] returns true for a
non-configurable descriptor, then the client can count on the property
being defined *as a non-configurable property*. It would not be OK for a
proxy to tamper with the descriptor that the client passed in (e.g. by
coercing configurable to true) and then signalling success, which seems
to be what WebIDL is doing here.

The prose says: A property cannot be added as or modified to be
non-configurable, if it does not exists as a non-configurable own property
of the target object.

Possibly we need to make more explicit the fact that added as
non-configurable pertains to the original attribute state that the client
passed in.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Violations of internal method invariants?

2014-07-30 Thread Tom Van Cutsem
Hi Boris,

It seems you're right (reproduced on Chrome and Safari). These examples
clearly violate all the invariants related to non-configurable properties.

If I understand correctly, the form DOM element's named input properties
'shadow' the actual JS properties defined on the DOM object. Even if the
DOM object defines a non-configurable foo property, adding an input
element with the name foo will shadow the non-configurable property with
a configurable one (and removing the input element again reveals the old
non-configurable JS property).

This seems bad. I'm not a DOM expert, but is it essential that the form
elements have two distinct namespaces (the namespace for named input
elements and for regular JS properties), or is this just a side-effect of
how they happen to be implemented?

Regards,
Tom


2014-07-28 18:04 GMT+02:00 Boris Zbarsky bzbar...@mit.edu:

 I was trying to determine what browsers do with named properties on form
 elements, and I'm getting some rather strange results.

 Consider https://bugzilla.mozilla.org/attachment.cgi?id=8463423 and
 https://bugzilla.mozilla.org/attachment.cgi?id=8463432

 Is it just me, or do Chrome and IE violate the internal method invariants
 on the first of those, and all three of Chrome, IE, Safari violate them on
 the second one?

 -Boris
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Reflect.hasOwn() ?

2014-07-28 Thread Tom Van Cutsem
2014-07-27 18:14 GMT+02:00 Mark S. Miller erig...@google.com:

 Although there is some interesting work in trying to obtain security
 relevant guarantees from a script that isn't first, where a malicious
 script may instead have been first (link please if anyone has it), this
 work did not seem practical to me.


Not sure if this is what you had in mind, but Sergio Maffeis has been
working on something along these lines:

DefensiveJS (DJS)
http://www.defensivejs.com

DJS is a defensive subset of JavaScript: code in this subset runs
independently of the rest of the JavaScript environment. When propertly
wrapped, DJS code can run safely on untrusted pages and keep secrets such
as decryption keys.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Reflect.hasOwn() ?

2014-07-26 Thread Tom Van Cutsem
2014-07-26 5:43 GMT+02:00 Axel Rauschmayer a...@rauschma.de:

 ECMAScript 6 mostly eliminates the need to call methods generically (no
 need to use the array-like `arguments`, `Array.from()`, spread operator,
 etc.).

 The only exception that comes to my mind is `{}.hasOwnProperty.call(obj,
 key)` (which is the only safe way to invoke this method). Would it make
 sense to provide that as a tool function, e.g. as `Reflect.hasOwn()`?


Reflect.hasOwn was actually included in the Reflect API initially, as the
dual to the Proxy hasOwn trap. When we decided to remove the trap, we
also threw out Reflect.hasOwn (in keeping with the symmetry between these
Reflect.* utilities and the Proxy traps).

The rationale to remove Reflect.hasOwn was that it could easily be
simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !== undefined).
While this conses a throw-away property descriptor object, the overhead was
deemed insignificant.

Overall, I'm leaning towards keeping the built-in Reflect API minimal.
There's room for many more utility methods (Reflect.getPropertyDescriptors
comes to mind) which can all be expressed as a library.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


TOCTTOU issue in Proxy invariant checks

2014-07-22 Thread Tom Van Cutsem
Hi,

While reviewing some changes to the Proxy spec in the latest revision, it
occurred to me there is a potential time-of-check-to-time-of-use (TOCTTOU)
issue in the Proxy invariant checks.

Concretely, take revision 26, section 9.5.12 [[OwnPropertyKeys]]:
- step 11 checks whether the target object is extensible
- this result then gets used in step 21 and 28 (if the target was
non-extensible, more invariant checks are made)
- in between steps 11 and 21/28, control is transferred to internal methods
of the target, which may itself be a Proxy and so trigger arbitrary user
code to run.
- hence, the extensibility state checked in step 11 might have changed
before being used in steps 21/28

I think the issue is benign, because extensibility can only ever change
from 'true' to 'false' but not vice versa. This means we can end up in the
following scenario:

- assume a proxy and its target are extensible when [[OwnPropertyKeys]] is
invoked
- step 11 checks the extensibility state and stores 'true'
- assume user code runs between steps 11 and 21 that calls
Object.preventExtensions on the target, so the extensibility state is now
really 'false'
- Then, in step 21, even though the target is now non-extensible, the
  algorithm terminates early and doesn't perform the invariant checks for
non-extensible objects.

I think this is benign because the caller of the internal method, at the
time it made the call, had no reason to assume strong invariants on the
proxy/target.

Basically, the way to think of this is that invariant checks are made based
upon the state of the target object when the internal method is first
invoked. While that internal method call is suspended, the target's state
may change, but invariant checks may still be based on the target's state
upon entry.

While I'm fairly confident the issue is benign, the reasoning is subtle and
could use more braincells to check if I missed anything.

This issue may appear for other Proxy internal methods, I haven't yet
checked. But generally I think they will also be benign for the same
reasons. An attacker can only modify the target to have stronger, not
weaker, invariants. Suspended calls that only assume weak invariants cannot
get confused if eventually more invariant checks are made.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: @@new

2014-06-18 Thread Tom Van Cutsem
I really like this proposal.

2014-06-17 21:32 GMT+02:00 C. Scott Ananian ecmascr...@cscott.net:

 +1.

 I think you could also remove the 'construct' handler in Proxy
 (
 http://people.mozilla.org/~jorendorff/es6-draft.html#sec-construct-internal-method
 step 4), as the @@new method can be handled with the usual proxy
 method dispatch mechanism.  I'll leave it to someone who better
 understands Proxies to give the details.


That's what Jason meant by getting rid of the `construct` trap.

cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: IsConstructor

2014-06-16 Thread Tom Van Cutsem
2014-06-13 19:21 GMT+02:00 Allen Wirfs-Brock al...@wirfs-brock.com:

 Anotherconcern I have with @@new, it that it exposes two extension points,
 @@new and @@create, on very constructor.  I'm afraid that it wouldn't be
 very clear to most ES programmers when you should over-ride one or the
 other.


Smalltalk has both extension points (#new and #initialize). I think JS
programmers could handle this just as well.


 Finally, let's say that for ES6 we eliminate [[Construct]] without adding
 @@new. If after some experience we find that @@new is really needed we can
 easily add it in a backwards compatible manner.


By that time, the community will have developed its own set of
work-arounds, as it always does.

In any case, I believe you're probably right that @@create + constructor
invocation is sufficient for most use cases. The crucial step is that if
the constructor returns an object, this is the object returned by |new
C(...args)|. This way, the constructor can always return a cached object
and ignore whatever dummy object was created by @@create. Correct?

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: IsConstructor

2014-06-13 Thread Tom Van Cutsem
Interesting. It'd be nice if we could further simplify the Proxy/Reflect
API. Given the local nature of these changes, we might still include it in
ES6 if we achieve quick consensus.

As Allen mentioned, this came up a number of times in TC39 meetings and I
believe the fear for exotic objects that require control over [[Construct]]
was the biggest show-stopper. If more knowledgeable people like Boris can
vouch for the fact that this isn't the case, that would remove the biggest
roadblock.

Scott is right: Reflect.construct essentially directly calls [[Construct]],
so the Reflect API already provides the power to construct objects without
the new operator. There are no security concerns that I can spot. Cc'ing
Mark.

One important detail:

Jason proposes:
new C(...args) = C[Symbol.new](...args)

Allen proposes:
   new C(...args) =  C.apply(C[Symbol.create](), args)

I prefer Jason's transformation for the following reason: imagine a proxy
that wants to implement e.g. a flyweight pattern (i.e. it wants to pool or
cache objects, rather than constructing a fresh object for each call to
|new|). This is trivial to do with Jason's transformation, because the
proxy is in control of *both* object allocation and initialization. With
Allen's transformation, we need to jump through some hoops if the cached
object returned by Symbol.create depends on args (which is common for
flyweights), as they only get passed in after Symbol.create returns.

We can debate whether C[Symbol.new] should be called with args collected in
an array or spliced. I have no preference.

Cheers,
Tom




2014-06-12 22:56 GMT+02:00 C. Scott Ananian ecmascr...@cscott.net:

 On Thu, Jun 12, 2014 at 3:21 PM, Allen Wirfs-Brock
 al...@wirfs-brock.com wrote:
  It's not obvious to me why we would need @@new in addition to @@create
 (which is pretty much equivalent to saying it's not clear to me why we need
 [[Construct]]). For the ordinary case, @@new would just be another level of
 method lookup and invocation that would be required on each new.  While we
 expect implementations to (eventually)  optimize all of this, we still
 tried to minimize the amount of boiler plate work required for each new.

 From my perspective, it's about simplifying the language.  I like the
 fact that 'new C' is just sugar for an ordinary method invocation on
 C.  It would simplify the presentation of the spec as well: various
 places that currently state special behavior for new XYZ forms could
 instead describe the ordinary method XYZ.@@new.   And as Jason points
 out, this conceptual simplification of the language translates into
 concrete API simplifications for reflective operations like Proxies.

 I don't think there are any special security issues involved, since I
 can already do: `let x = Reflect.construct.bind(Reflect, C)` and pass
 that around.
   --scott

 (fwiw, Crockford's Simplified JavaScript in
 http://javascript.crockford.com/tdop/tdop.html and my own
 TurtleScript subset of JavaScript in
 https://github.com/cscott/TurtleScript both did away with the new
 operator.  TurtleScript replaced it with `Function#New`.)
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: IsConstructor

2014-06-11 Thread Tom Van Cutsem
2014-06-11 16:48 GMT+02:00 Erik Arvidsson erik.arvids...@gmail.com:


 [*] Proxies are oddballs here. All Proxies have a [[Construct]] method so
 the IsConstructor will always return true which is really not what you
 want. If IsConstructor was changed to check for a .prototype instead
 proxies would behave more inline with ordinary objects.


No, only proxies whose target has a [[Construct]] method will themselves
have a [[Construct]] method. IOW, proxies should be completely transparent
w.r.t. the IsConstructor test.
See 9.5.15 ProxyCreate step 5.b.

I believe there may be a spec bug, as step 4 should explicitly exclude
[[Construct]] and [[Call]], yet seems to include all methods defined in sec
9.5. Allen?

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: IsConstructor

2014-06-11 Thread Tom Van Cutsem
2014-06-11 18:02 GMT+02:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 Kind of boarder line.  6.1.7.2 says that the essential internal methods
 are those listed in Table 5 (does not include [[Call]] and
 [[Constructor]]).  Also the definitions of [[Call]] and [[Construct]] in
 9.5 each include a note that says these internal methods are only provided
 when a corresponding internal method exists on the target.

 Reading the section as a while, I think it is pretty clear that  that a
 Proxy only has a [[Construct]] internal method if its target also has one.


Ok, the fact that an explicit note is included in 9.5.13 [[Call]] and
9.5.14 [[Construct]] should be sufficient to avoid any doubt.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.getOwnPropertyDescriptor can return just about anything

2014-05-09 Thread Tom Van Cutsem
Rick,

It's true that allowing user-invented custom attributes will not break any
important existing invariants (except perhaps that all existing descriptors
can be assumed not to have any own properties besides the standard
attributes. Existing code may depend on that, although it feels highly
unlikely).

Cheers,
Tom



2014-05-09 0:11 GMT+02:00 Rick Waldron waldron.r...@gmail.com:




 On Thu, May 8, 2014 at 5:23 PM, Tom Van Cutsem tomvc...@gmail.com wrote:

 Allen, Mark and I discussed the [[Origin]] issue and came to the
 following consensus:

 We remove [[Origin]] and revert to the originally specified behavior (
 http://wiki.ecmascript.org/doku.php?id=harmony:proxies_spec) where the
 descriptor returned by the proxy is coerced into a fresh, normalized,
 completed, ordinary descriptor object.

 This ensures complete backward-compatibility with the ES5 behavior (i.e.
 Object.getOwnPropertyDescriptor will always return a fresh, complete data
 or accessor descriptor), and doesn't allow a proxy to play tricks with
 descriptor objects.

 Allen's remaining concern is that this disallows proxies (or new exotic
 objects) from inventing new types of descriptors, next to data and accessor
 descriptors. Due to backwards-compat. constraints, we're basically stuck
 with these two types of property descriptors forever.

 The originally specified Proxy behavior also included copying any
 non-standard attributes provided by the proxy onto the fresh descriptor
 object. However, if we're serious about keeping
 Object.getOwnPropertyDescriptor backwards-compatible with existing ES5
 code, we may be better off by not augmenting descriptor objects with
 non-standard attributes, even if this is unlikely to break existing code.
 As Jason mentioned, if proxies want to introduce new per-property
 attributes, they can provide other means of getting at that meta-data
 rather than abusing the standard reflection API.

 So, the current proposal is to spec [[GetOwnProperty]] for Proxies such
 that the descriptor returned by the trap is coerced into a fresh,
 normalized, complete descriptor object, without copying custom attributes.

 Relevant bug seems to already have been filed by Andre: 
 https://bugs.ecmascript.org/show_bug.cgi?id=2382


 Forgive me if this has already been discussed elsewhere, but the Notes
 section of [[GetOwnProperty]](P) lists several invariants that are similar
 in nature to the following (which I've just made up):

 - A property cannot be reported as configurable, if it does not exists as
 an own property of the target object or if it exists as a non-configurable
 own property of the target object.

 - A property cannot be reported as writable, if it does not exists as an
 own property of the target object or if it exists as a non-writable own
 property of the target object.

 - A property cannot be reported as enumerable, if it does not exists as an
 own property of the target object or if it exists as a non-enumerable own
 property of the target object.


 Then descriptors would allow user-invented descriptor properties, while
 still upholding the target's integrity.


 Rick


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.getOwnPropertyDescriptor can return just about anything

2014-05-09 Thread Tom Van Cutsem
2014-05-09 9:57 GMT+02:00 David Bruant bruan...@gmail.com:

 Just to try to assess the unlikelihood and understand the cases where a
 ES5 code expectations aren't met:

 The only case where ES6 and ES5 may diverge is for 
 Object.getOwnPropertyDescriptor
 where a Proxy may return something that cannot be expected from any ES5
 object.
 The after-trap completes the property descriptor (and when completing
 picks specifically only data or accessor property), so code that expects a
 complete property descriptor cannot be broken.
 However, a divergence may only occur if, for instance, the code loops over
 the property descriptor properties or expects exactly 4 properties.

 Is that correct or am I missing cases?


Another possibility would be that existing client code itself extends
property descriptors with new attributes (since descriptors returned by
gOPD are always extensible), and can then get confused when proxies
pre-populate these descriptors with their own custom attributes. But again,
this is highly unlikely. I think allowing proxies to accept/return custom
attributes remains feasible.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.getOwnPropertyDescriptor can return just about anything

2014-05-08 Thread Tom Van Cutsem
Allen, Mark and I discussed the [[Origin]] issue and came to the following
consensus:

We remove [[Origin]] and revert to the originally specified behavior (
http://wiki.ecmascript.org/doku.php?id=harmony:proxies_spec) where the
descriptor returned by the proxy is coerced into a fresh, normalized,
completed, ordinary descriptor object.

This ensures complete backward-compatibility with the ES5 behavior (i.e.
Object.getOwnPropertyDescriptor will always return a fresh, complete data
or accessor descriptor), and doesn't allow a proxy to play tricks with
descriptor objects.

Allen's remaining concern is that this disallows proxies (or new exotic
objects) from inventing new types of descriptors, next to data and accessor
descriptors. Due to backwards-compat. constraints, we're basically stuck
with these two types of property descriptors forever.

The originally specified Proxy behavior also included copying any
non-standard attributes provided by the proxy onto the fresh descriptor
object. However, if we're serious about keeping
Object.getOwnPropertyDescriptor backwards-compatible with existing ES5
code, we may be better off by not augmenting descriptor objects with
non-standard attributes, even if this is unlikely to break existing code.
As Jason mentioned, if proxies want to introduce new per-property
attributes, they can provide other means of getting at that meta-data
rather than abusing the standard reflection API.

So, the current proposal is to spec [[GetOwnProperty]] for Proxies such
that the descriptor returned by the trap is coerced into a fresh,
normalized, complete descriptor object, without copying custom attributes.

Relevant bug seems to already have been filed by Andre: 
https://bugs.ecmascript.org/show_bug.cgi?id=2382

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Tom Van Cutsem
2014-05-05 19:40 GMT+02:00 John Barton johnjbar...@google.com:

 I'm hoping someone can explain this result which surprises me.

 If I create an object with a Proxy-ed prototype, the resulting object does
 not obey .__proto__ equal Object.getPrototypeOf().


There's no such equivalence, even for regular objects. `__proto__` is just
a property name, so `proxy.__proto__` just triggers the get trap, as any
normal property access. If the proxy should treat it specially, you need to
special-case the name `__proto__` in the get trap. However, as Allen
points out, forwarding should work correctly as long as you also forward
the receiver binding using the Reflect.get method.


 At this point, I expected
   hasProxyAsProto.__proto__ === aProxy
 but it it not true.  Moreover, the operation
   hasProxyAsProto.__proto__
 calls the Proxy handler get function with name === '__proto__': that makes
 no sense as hasProxyAsProto is not a Proxy.


If an object inherits from a proxy, then any property access for a non-own
property will traverse the prototype chain. If it hits a proxy, that
proxy's get trap is called.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.getOwnPropertyDescriptor can return just about anything

2014-04-30 Thread Tom Van Cutsem
2014-04-30 3:29 GMT+02:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 Again, there is nothing new here.  At the very least you should look at
 the old discussion about this.


Pointers to the old discussions:

I first commented on [[Origin]] as part of my review of the first ES6 draft
Proxy spec:
https://mail.mozilla.org/pipermail/es-discuss/2012-December/027623.html

The thread then forked:
https://mail.mozilla.org/pipermail/es-discuss/2012-December/027708.html
https://mail.mozilla.org/pipermail/es-discuss/2013-January/027788.html

Unfortunately, the conversation was a ping-pong between just me and Allen,
with me pushing back on the idea and Allen eventually proposing a
middle-ground alternative that I felt somewhat uncomfortable with, but
seemed to be addressing the major concerns.

Reading the conversation again, both Allen and me failed to convince each
other, we ran out of arguments ammo, and so ended up with a compromise. It
would be good if others chimed in.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.getOwnPropertyDescriptor can return just about anything

2014-04-30 Thread Tom Van Cutsem
2014-04-30 18:55 GMT+02:00 Mark Miller erig...@gmail.com:

 This is a stop-the-train scale disaster. ES6 cannot ship in this state. We
 need to fix this asap.


I agree we need to revisit and iron out the details asap, but keep your
calm. I'm sure we'll be able to fix this well in time before the ES6 spec
is frozen. This is a very localized spec issue.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.entries(), Object.values()

2014-03-25 Thread Tom Van Cutsem
2014-03-22 3:14 GMT+01:00 C. Scott Ananian ecmascr...@cscott.net:

 Sorry for the confusion.  I was actually referring to
 [[OwnPropertyKeys]] returning an Array, as discussed previously:

 http://esdiscuss.org/topic/object-getownpropertydescriptors-o-plural#content-34

 Presumably the corresponding proxy trap would change to return an Array as
 well.

 But this is a bit off-topic for Object.entries/Object.values ---
 although related in the sense that the [[OwnPropertyKeys]] returns
 Array proposal also got support (and a +1 from be) on the list, but
 hasn't been formally added to the ES6 agenda as far as I can tell.


Thanks for digging this up. I'll add it to the agenda.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enriched Descriptors, maybe ES7 ?

2014-03-10 Thread Tom Van Cutsem
2014-03-09 21:05 GMT+01:00 Brendan Eich bren...@mozilla.com:

 Tom has experimented, IIRC. I don't know which implementations preserve
 extended property descriptor properties.


As Allen mentioned earlier, proxies should receive in their defineProperty
trap the full descriptor object as it was passed in by the user, including
any custom attributes. The proxy is free to store it, and return it from
any subsequent getOwnPropertyDescriptor trap (which is also specced so that
it can return a non-normalized descriptor object with custom attributes).

Normal (non-proxy) objects of course cannot store non-normalized
descriptors, so any custom attributes are lost. Changing this would
presumably have a big impact on implementations (which probably don't hang
on to descriptor objects at all).

If you want to experiment with custom attributes, my harmony-reflect shim
supports this for proxies:

var props = {};
var o = new Proxy({},{
  defineProperty: function(target, name, desc) {
props[name] = desc;
return true;
  },
  getOwnPropertyDescriptor: function(target, name) {
return props[name];
  }
});
Object.defineProperty(o,p,{value:42, configurable:true, hello:true})
JSON.stringify(Object.getOwnPropertyDescriptor(o,p))
// prints
// {configurable:true,
//  value:42,
//  writable:false,
//  enumerable:false,
//  hello:true } // - custom attribute preserved

Using Firefox's built-in direct proxies implementation I get a TypeError.
I'll investigate further and file a bug.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enriched Descriptors, maybe ES7 ?

2014-03-10 Thread Tom Van Cutsem
2014-03-10 11:10 GMT+01:00 David Bruant bruan...@gmail.com:

 Using Firefox's built-in direct proxies implementation I get a TypeError.
 I'll investigate further and file a bug.
 You already did https://bugzilla.mozilla.org/show_bug.cgi?id=601379 ;-)


Thanks for refreshing my memory on that one ;-)

But that was actually not the bug that caused my earlier code snippet to
fail. Instead it's this bug (already reported by Eddy Bruel):
https://bugzilla.mozilla.org/show_bug.cgi?id=793210

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.getOwnPropertyDescriptors(O) ? // plural

2014-03-07 Thread Tom Van Cutsem
2014-03-07 0:51 GMT+01:00 C. Scott Ananian ecmascr...@cscott.net:

 On Thu, Mar 6, 2014 at 6:31 PM, André Bargull andre.barg...@udo.edu
 wrote:
  On 3/6/2014 11:35 PM, Andrea Giammarchi wrote:
  The proposed [[GetOwnPropertyNames]] internal method is supposed to be a
  more restrictive version of [[OwnPropertyKeys]] to ensure Proxy objects
  don't lie about their properties.

 [[SafeOwnPropertyKeys]] or [[CheckedOwnPropertyKeys]] seems like a
 more accurate and less confusing name, since it returns keys not
 names.


The result is only checked for proxies, but the name of internal methods
should make sense for all types of objects.

From an API point of view, the more significant difference may be that
[[OwnPropertyKeys]] returns an iterable, while [[CheckedOwnPropertyKeys]]
would return an array of strings and symbols. I don't think there is
currently a good naming convention to distinguish things that return an
iterable versus things that return an array.

I searched the spec for all clients of [[OwnPropertyKeys]], they are:

Object.assign(target, source) // to iterate over all own props (strings and
symbols) of source
Object.keys(O) // to construct array of strings (of enumerable properties)
Reflect.ownKeys(O) // to get iterator over strings and symbols

// the following should be reliable primitives, thus should use the
checked version that returns an array:
Object.getOwnPropertyNames(O) // to construct array of strings
Object.getOwnPropertySymbols(O) // to construct array of symbols
Object.{freeze,seal}(O) // to reliably redefine all own props
Object.{isFrozen,isSealed}(O) // to reliably test all own props

Given that most of the functions that use [[OwnPropertyKeys]] need to
either construct an array anyway, or want reliable results, I wonder
whether we shouldn't just change [[OwnPropertyKeys]] to include the checks
and return an array instead of an iterable. That way we avoid having two
internal methods that do more or less the same thing.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Object.getOwnPropertyDescriptors(O) ? // plural

2014-03-05 Thread Tom Van Cutsem
2014-03-05 20:11 GMT+01:00 C. Scott Ananian ecmascr...@cscott.net:

 On Wed, Mar 5, 2014 at 1:39 PM, Tom Van Cutsem tomvc...@gmail.com wrote:
  Object.getOwnPropertyDescriptors(proxy) would trigger the
  getOwnPropertyNames trap, followed by calls to the
 getOwnPropertyDescriptor
  trap for each individual property.

 [[OwnPropertyKeys]], `ownKeys` trap.


Yes, according to the current draft spec. I have a pending discussion with
Allen that we actually need to reintroduce a [[GetOwnPropertyNames]]
internal method / getOwnPropertyNames trap, as the `ownKeys` trap doesn't
do any invariant checking, which is needed for a reliable Object.isFrozen
test.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: ES6 Tasks and TaskQueues

2014-03-04 Thread Tom Van Cutsem
The benefit of turn is that I've seen this terminology used almost
exclusively for denoting an atomic turn of an event loop (tick is also
often used). By contrast, terms such as task are used much more broadly
(e.g. tasks scheduled on a thread pool). Just my 2c.


2014-03-04 19:47 GMT+01:00 Mark S. Miller erig...@google.com:

 On Tue, Mar 4, 2014 at 10:39 AM, Tab Atkins Jr. jackalm...@gmail.comwrote:

 On Tue, Mar 4, 2014 at 5:59 AM, Claude Pache claude.pa...@gmail.com
 wrote:
  Le 24 févr. 2014 à 19:40, Allen Wirfs-Brock al...@wirfs-brock.com a
 écrit :
  I don't think this use of the word turn is broadly enough known to
 provide many spec. readers an immediate intuitive feeling for the concept.
 
  It seems to me that the word turn is widely used in that sense for
 turned-based games such as chess, so that it has a good chance to be
 understood. Or am I mistaken?

 I agree with Claude and others who feel that turn is confusing


 Hi Tab, you are reading Claude's message in the opposite way that I am.

 Hi Claude, which did you mean?




 - in
 every outside use of turn as a noun, it refers to the time-slice in
 which you take actions, not the actions themselves.  It is sometimes
 used slangily to refer to the things you did during the timeslice,
 like Argh, your turn destroyed my plan, now I've got to think more.,
 but in general using turn to refer to an action feels extremely
 weird to me.

 At least for me, this intuition comes from my long experience as a
 gamer of various sorts - this usage applies equally to card games,
 board games, video games, etc.


 I won't die if it ends up getting used, but I'd greatly prefer a
 different term.

 ~TJ




 --
 Cheers,
 --MarkM

 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: New ES6 spec draft (Rev 22, Jan 20, 2014)

2014-01-21 Thread Tom Van Cutsem
I really like the way the ES6 spec is coming together. Generally the way in
which abstract ops are used and internal methods are specified is much
clearer and more uniform in ES6 than in ES5. Also, the table of contents is
much better structured. I like your classification according to indexed
collections, keyed collections, control abstraction objects, reflection,
etc. These editorial issues are not always fully appreciated, but +1 to
them.

Cheers,
Tom


2014/1/21 Allen Wirfs-Brock al...@wirfs-brock.com

 The draft is available at
 http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#january_20_2014_draft_rev_22


 Big news: Promise and Module Loading/Linking.  Still a few loose ends, but
 we're getting there.

  Changes include:

- Promises
 - Module loading/linking semantics
 - Internal Tasks
 - Realm Objects
 - Loader Objects
 - updated with binding for unscopable names as discussed at Sept 2013
meeting
 - An unscopables object is now an ordinary object whose own property
keys are the unscopable names.
 - Fixed sticky mode bugs in RegExpExec
 - Provided algorithm for RegExp.prototype.replace and updated other
RegExp methods
 - Fixed RegExp matcher algoritm to normalize results of Unicode mode
matches back to UTF-16
 - Grammar parameter tweaks related to use of yield in generator
parameters.
 - Simplified eval/arguments restrictions. They never are applied in
non-strict code
 - Added tail call detection for arrow functions with expression bodies
 - clarified unicode escaping in IdentifierNames and keywords
 - The default class constructor definition is now
“constructor(...args) {return super (...args);)” if one is not explicitly
provided (adding explicit “return” is the change)
 - Fixed Invoke abstract operation to correctly handle invokes on
primitive values. Implementations of built-ins that are * specified using
Invoke should make sure they work correctly in cases where Invoke might be
validly applied to a primitive
 - Function.prototype.toMethod, replaces RebindSuper abstraction
operation with CloneMethod
 - Eliminated comparator optional argument to Map and Set constructor
 - Removed vague overflow/underflow requirements from Math.Hypoth
 - Creating a Proxy requires use of new.
 - No line terminator allow before the * in yield *.
 - extends clause of a class declaration is now a
LeftHandSideExpression
 - Completely redo of object invariants section.



 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Reflect.* naming: defineProperty, deleteProperty vs. get, has, set?

2014-01-03 Thread Tom Van Cutsem
'deleteProperty' was in fact originally called 'delete'. We changed it to
avoid a conflict with the keyword, which occurs when importing the function
(recall that the Reflect.* methods are actually functions exported from a
module). While ES5 made it possible to use keywords as properties, you
obviously still can't use keywords as ordinary function names.

defineProperty is by symmetry with the existing Object.defineProperty
built-in. I believe the symmetry is more important than a shorter name.

Cheers,
Tom


2014/1/3 Domenic Denicola dome...@domenicdenicola.com

  It seems like it would be nicer to change the former to define and
 delete, respectively?

 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[OwnPropertyKeys]]

2013-12-08 Thread Tom Van Cutsem
2013/12/8 Brendan Eich bren...@mozilla.com

 We did not have consensus on per-object Get/SetIntegrity. I don't think we
 want the redundancy entailed. Implementors I've spoken with do not. This
 seems a dead snake, so no need to shoot at it.


Thanks for digging up those links. Indeed, no need to revisit this. The
only requirement is that the abstract algorithms TestIntegrity and
SetIntegrity in the current ES6 draft use a reliable internal method for
querying the object's own properties (i.e. something like
[[GetOwnPropertyNames]] rather than [[OwnPropertyKeys]]).

@Mark: you are right about the additional restriction. W.r.t. invariant
checks on proxies, I believe this implies that once a proxy's target is
non-extensible, the handler must return from its getOwnPropertyNames trap
exactly the set of properties returned from
Object.getOwnPropertyNames(target). That is: proxies cannot virtualize the
list of properties for non-extensible objects. While this may seem awkward
at first, this is precisely the restriction that we need so that
Object.freeze and isFrozen remain reliable in the presence of proxies.

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[OwnPropertyKeys]]

2013-12-07 Thread Tom Van Cutsem
As currently specified, [[OwnPropertyKeys]] doesn't have any particular
invariants on the values it generates from the returned iterator.

Mark and I proposed to reintroduce [[GetOwnPropertyNames]] as a separate
internal method, which would return an array rather than an iterator, but
which would also be required to return at least the names (symbols or
strings) of all non-configurable properties. The switch to an array return
value is motivated partly by the reasons Jason stated, but also because
actually checking the invariant requires exhausting the iterator anyway.

[[OwnPropertyKeys]] would continue to return an iterator (or iterable , as
Jason suggests, which seems to make more sense), but there would be no
invariants on its generated values.

[[GetOwnPropertyNames]] would be the reliable way of querying an object for
its own properties, and would be used at least by
Object.getOwnPropertyNames and the abstract operations used by
Object.{freeze,isFrozen,seal,isSealed}, so that the result of these
operations can in turn be made reliable.

[[OwnPropertyKeys]] can be used for all other operations that don't need
the invariant that all non-configurable properties should be
listed/generated.

Cheers,
Tom


2013/12/6 Allen Wirfs-Brock al...@wirfs-brock.com

 I'm working with TomVC right now on revising these internal methods.  More
 on that soon.

 One possible advantage of using an Iterator is that large dense indexable
 objects such as typed arrays, strings, or similar abstractions defined
 using a proxy don't have to instantiate an
 Array containing huge numbers of  element indices.

 Also we have talk about, the future addition of user land iterator valued
 functions such as keys, ownKeys, etc.  or the possibility of frameworks
 providing such functions.  The internal methods.  The MOP defined by the
 internal methods should provide a stable foundation for such future
 extensions.

 Allen


 On Dec 6, 2013, at 6:35 AM, Jason Orendorff wrote:

  It looks like [[OwnPropertyKeys]] is defined to return an iterator.
  But the ordinary [[OwnPropertyKeys]] method produces the List of keys
  to be iterated eagerly, and pretty every place that calls the method
  immediately consumes the entire iterator. So there is no actual
  laziness.
 
  This is weird. I think it would be clearer for [[OwnPropertyKeys]] to
  return a List of PropertyKeys.
 
  Except for proxies, this doesn't change behavior. Here are the changes
  needed to implement this:
 
  * In 9.1.12, the ordinary object [[OwnPropertyKeys]] method, change
  step 3 to just say Return keys. instead of Return
  CreateListIterator(keys).
 
  * In 9.5.12, the Proxy [[OwnPropertyKeys]] method, treat the return
  value as an iterable (not an iterator) and convert it to a List of
  PropertyKeys using IteratorStep, IteratorValue, and ToPropertyKey.
  Change the NOTE to describe the new invariant.
 
  * In 19.1.2.1 Object.assign, 19.1.2.8.1 GetOwnPropertyKeys, 19.1.2.14
  Object.keys, and 19.1.2.15.1 MixinProperties, drop the IteratorStep
  boilerplate.
 
  * In 26.1.10 Reflect.ownKeys(), convert the result of calling
  [[OwnPropertyKeys]] to an Array using CreateArrayFromList.
 
  Note that 7.3.10 SetIntegrityLevel and 7.3.11 TestIntegrityLevel
  already assume that [[OwnPropertyKeys]] returns a List, as proposed.
 
  -j
  ___
  es-discuss mailing list
  es-discuss@mozilla.org
  https://mail.mozilla.org/listinfo/es-discuss
 

 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Reflecting on object properties

2013-12-07 Thread Tom Van Cutsem
I share your concern (I already got confused when there were just
Object.gOPN and Object.keys), but I'm skeptical that we can break the
behavior of existing Object.* methods.

You actually forgot Reflect.enumerate, which returns an iterator for all
the own and inherited enumerable properties ;-)

Perhaps one easy to remember distinction is that the Object.* methods
return arrays whereas the newer Reflect.* methods return iterators (or
iterables).

Cheers,
Tom


2013/12/6 Till Schneidereit t...@tillschneidereit.net

 In addition to what Jason just posted about [[OwnPropertyKeys]], I think
 there are some avoidable inconsistencies in how the various object
 properties reflection methods are specified. As specified or proposed right
 now, we have three different such functions: Object.keys,
 Object.getOwnPropertyNames, and Reflect.ownKeys. Here's their respective
 behavior:

 Object.keys: returns an array of keys of all the iterable own string-keyed
 properties of the given object

 Object.getOwnPropertyNames: returns an array of keys of all the own
 string-keyed properties of the given object

 Reflect.ownKeys: returns an iterator over all the keys of own string- or
 symbol-keyed properties of the given object

 I.e., Reflect.ownKeys behaves more like Object.getOwnPropertyNames, except
 that it returns an iterator, and returns symbols, too. Under Jason's
 proposal, it'd at least not return an iterator.

 While I see that it's a migration hazard for Object.keys and
 Object.getOwnPropertyNames to return symbols, too, I think the long-term
 hazard introduced by the subtle differences between these three methods is
 of greater concern. There's just no way to tell from their names what the
 precise behavior will be, and the differences are subtle enough that
 they'll be hard to remember. For proxies, it's hard to tell which trap has
 to be implemented to affect the behavior of any one of these methods.

 Hence, I think Object.keys and Object.getOwnPropertyNames should return
 symbols, too. Proxies wouln't need to get a new trap at all. The migration
 hazard should actually be somewhat mitigated by the fact that many use
 cases should continue to just work in the face of symbols, while many
 others should fail fairly obviously. Since I don't have data to base this
 on, I want to reiterate that the long-term hazard of having three
 irritatingly similar but different methods is the real argument I'm making.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Proxies and bind (Was: November 20, 2013 Meeting Notes)

2013-11-27 Thread Tom Van Cutsem
I wasn't there on day 2 so I may be lacking context, but I'd like to
clarify some parts in the notes re. proxies and Function.prototype.bind:

2013/11/27 Rick Waldron waldron.r...@gmail.com

 EA: What happens when do bind on a function proxy?

 MM: fail?

 DH: This is shocking.

 MM: bind is a perfect example, there is no conflict between security and
 transparency. You'd like bind to work on proxy functions


Not sure why Mark mentioned that bind fails on function proxies. It doesn’t:

js var o = {}
js var p = new Proxy(function() { return this; }, {})
js var f = p.bind(o)
js f() === o
true

(and this works regardless of whether you use p.bind(o) or
Function.prototype.bind.call(p,o))

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: November 19, 2013 Meeting Notes

2013-11-27 Thread Tom Van Cutsem
2013/11/27 David Bruant bruan...@gmail.com

 Le 27/11/2013 19:14, Rick Waldron a écrit :


 BE: typeof depends if there is a call trap. instanceof depends on the
 prototype chain. All in the spec, so can create any object (apart from
 private state issues)

 Shouldn't it depend on the target's typeof value? depending on apply (not
 call) trap makes typeof unstable (delete handler.apply).
 In any case, extra caution is required to keep typeof stability for
 revokable proxies (on revocation, maybe the value need to be saved
 somewhere)


No, the current ES6 draft I believe gets it right:

- typeof proxy does not depend on the presence of an apply trap, but on
whether the target object has a [[Call]] internal method. So deleting
handler.apply has no effect on the typeof value of the proxy. (see 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-typeof-operator-runtime-semantics-evaluation
)

(the current draft does lose the ability for a proxy to transparently
retain a non-standard typeof value. AFAICT, typeof proxy will always either
return object or function)

- a proxy whose target has a [[Call]] internal method will itself have a
[[Call]] internal method. If the target does not have a [[Call]] internal
method, then neither does the proxy (see 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-proxycreate)

- revoking a revocable proxy does not change whether or not it has a
[[Call]] trap (see 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-proxy-revocation-functions),
so the typeof result will remain stable even when the proxy is revoked.

nit:

 instanceof depends on the prototype chain
 = Note that it calls the getPrototypeOf trap which doesn't enforce
 anything for extensible objects [1], so *the* prototype chain has a more
 volatile meaning for proxies than it has for regular objects.


Indeed, but only for proxies that claim to be extensible. For
non-extensible proxies, the prototype chain is well-defined.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Weak callbacks?

2013-11-15 Thread Tom Van Cutsem
2013/11/11 Mark S. Miller erig...@google.com

 Much of the early Actors research
 DEC SRC Network Objects
 RMI
 Original-E before I arrived at Electric Communities
 Midori
 Orleans
 AmbientTalk
 Cap'n Proto


While I'm honored to see AmbientTalk listed among these systems, I should
note that, pertinent to this discussion, AmbientTalk made exclusive use of
leasing to manage distributed resources. There was no other form of DGC. It
was partly inspired by the leasing policies in .NET Remoting (.NET's
counterpart of Java RMI).

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Weak callbacks?

2013-11-15 Thread Tom Van Cutsem
2013/11/13 Mark S. Miller erig...@google.com

 * Weak consistency (I know, people hear CAP and give up too much) won,
 which surprised some.

 Because Promises are asynchronous, even locally, the state of the world
 when a promise-based request is made differs from the one in which the
 request is received. Since partition induces rejection of all promises
 across that partition, connection recovery takes distinct paths through the
 code where one copes, in an application dependent manner, with having been
 out of communication.

 Further support for weak consistency should come at a higher level, e.g.,
 via the Unum model 
 https://www.cypherpunks.to/erights/talks/uni-tea/uni-tea.ppt. Promises
 are a good substrate on which to build Una.


One of the most compelling approaches I've seen to date to enable eventual
consistency at a higher level is the recent work out of Microsoft Research
on cloud (data)types.
See http://research.microsoft.com/apps/pubs/default.aspx?id=163842. Tim
Coppieters, a student of mine, recently implemented the model as a pure JS
library, enabling easy replication of state among client and server
(node.js). His CloudTypes.js library is available at 
https://github.com/ticup/CloudTypes. I'm pretty excited about the
elegance/simplicity of the model. The library is well-documented. Worth a
look for those into distributed systems.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls, once more

2013-10-21 Thread Tom Van Cutsem
To confirm what Allen already mentioned: I too concluded from the
discussion that we would remove [[Invoke]] from ES6.

It is one of a few items I would like to put on the agenda of the TC39
November meeting to get a definitive consensus (the other item being the
removal of the hasOwn() trap, for which there also was consensus on the
list).

Regards,
Tom



2013/10/18 Allen Wirfs-Brock al...@wirfs-brock.com


 On Oct 18, 2013, at 11:06 AM, Brandon Benvie wrote:

  On 10/18/2013 11:01 AM, Allen Wirfs-Brock wrote:
  What your question does help me be more decisive on: We should not be
 in a rush to add an Invoke, InvokeFunction, or any new traps not needed for
 membranes, and not subject to a long history of examination. Invoke at
 least, as a derived trap, can always be added later, after ES6.
 
  Isn't there observably different behavior different depending on whether
 invoke exists or not? Even if you don't implement it in your handler? If
 that's the case, then it's not guaranteed that it can be added later down
 the line.

 Yes, and those differences are not easily fixable in the context of the
 current Proxy design.  As currently defined, some possible uses of Proxies
 will be broken regardless of whether or not [[Invoke]] is there.   Yet,
 the only reason to add [[Invoke]] at this time would be to try to fix
 issues with Proxies but even with [[Invoke]] we still have issues.  And.
 for ES6, we're run of time for experimenting with fixes.  However, as Mark
 pointed out, experts can make them work for specific use cases and they are
 essential for supporting membranes. So we can live with the exiting design
 (without [[Invoke]]) as an expert feature for building membranes and
 similar use cases.

 If we ever come up with a better design (perhaps including [[Invoke]]) we
 can always introduce a new kind of proxy that works with it.

 Allen
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls, once more

2013-10-21 Thread Tom Van Cutsem
2013/10/18 Till Schneidereit t...@tillschneidereit.net

 I share this concern. Last time we discussed it, Brendan said that we
 could implement it by falling back to .get if .invoke isn't
 defined[1]. I'm not sure how well that fits into the rest of the Proxy
 design, though.


It doesn't fit the direct proxies design (which wants to forward to the
target by default for missing traps), but it does fit the old proxy design
(where the proxy would indeed fall back to more primitive traps if more
specialized traps were missing). There is a case to be made for switching
designs for backwards-compat reasons. It would be symmetry breaking but it
would give us the necessary leeway to evolve the API. Worst-case, as Allen
mentioned, we can introduce a distinct proxy constructor.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: has the syntax for proxies been finalized ?

2013-10-21 Thread Tom Van Cutsem
2013/10/18 Rick Waldron waldron.r...@gmail.com

 @Tom - since you know the status of the more recent Proxy wiki pages
 better than I do, would you mind adding the same h1 text to those that fit
 the description of obsolete? Thanks!


Done!
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: has the syntax for proxies been finalized ?

2013-10-21 Thread Tom Van Cutsem
2013/10/18 Allen Wirfs-Brock al...@wirfs-brock.com

 This is what I currently have in my working draft of the ES6 spec:

 [...]

 In other words:
   you can say:
Proxy(traget,handler)
   but not
 new Proxy(target, handler)

 It would be easy enough to allow
 new Proxy(target,handler)
 but I'm not sure it is the best way to expose the Proxy abstraction .

 Proxy really isn't a class.  There is no Proxy.prototype object and  obj
 instanceof Proxy isn't useful. Also the @@create protocol really isn't
 right for instantiating Proxies.  Subclassing a Proxy isn't going to give
 you anything that is useful.


I agree with your line of reasoning and I would be happy if proxies can be
created without `new`. However, I don't see how the above spec disallows
the use of `new`. With the above definition, won't `new Proxy(target,
handler)` just work? (since the Proxy function just ignores its
`this`-binding?)

Regards,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: has the syntax for proxies been finalized ?

2013-10-21 Thread Tom Van Cutsem
2013/10/21 Allen Wirfs-Brock al...@wirfs-brock.com

 see
 http://people.mozilla.org/~jorendorff/es6-draft.html#sec-standard-built-in-ecmascript-objects

 Paragraph 9:

 Built-in functions that are not identified as constructors do not
 implement the [[Construct]] internal method unless otherwise specified in
 the description of a particular function.


Got it, thanks.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: has the syntax for proxies been finalized ?

2013-10-18 Thread Tom Van Cutsem
Proxy.create and Proxy.createFunction are deprecated.

The correct syntax is `new Proxy(target, handler)`

In my original direct proxies proposal, the `new` was optional, so that
`var p = Proxy(target, handler)` works equally well (cf. 
http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies)

Since then, it seems people want to move away from implicit construction
(since it doesn't interact well with class inheritance), so I don't know if
there is still consensus on this.

In the prototype Firefox implementation, `new` is currently mandatory.

Regards,
Tom


2013/10/18 Angus Croll anguscr...@gmail.com

 I couldn't find a commitment to a specific syntax in the latest ES6
 standard

 Gecko, chrome experimental, traceur and 'node --harmony-proxies' support
 the Proxy.create syntax (detailed in
 http://wiki.ecmascript.org/doku.php?id=harmony:proxies)

 e.g.
 var proxy = Proxy.create({
  get: function(p, n) {
   return 'Hello ' + n;
  }
 });
 proxy.World //'Hello World'

 However MDN calls the above the 'Old Proxy API'.
 Gecko also supports what MDN indicates implies is the current Proxy
  syntax (i.e. new Proxy)
 e.g.

 var p = new Proxy(
   {},
   {get: function(p,x) {
 return 'Hello ' + x
   }}
 );
 p.World; //'Hello World'

 Which is right?
 thanks


 @angustweets

 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Multiple globals and changing prototypes

2013-10-16 Thread Tom Van Cutsem
The relevant invariant for [[SetPrototypeOf]] is that if the target is
non-extensible, and the operation returns true (i.e. appears to succeed),
then [[GetPrototypeOf]] must return the same result as the value passed
into [[SetPrototypeOf]].

This is what I got from the current ES6 draft: 
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-proxy-object-internal-methods-and-internal-data-properties-setprototypeof-v


It is always OK for [[SetPrototypeOf]] to return false to indicate
reparenting is not possible.

Regards,
Tom



2013/10/16 Allen Wirfs-Brock al...@wirfs-brock.com


 On Oct 16, 2013, at 7:25 AM, Mark S. Miller wrote:

 Keep in mind that if an object is non-extensible, its [[Prototype]] cannot
 be changed.


 And objects that are implemented using a Proxy don't use their
  [[Prototype]] slot (a Proxy they doesn't have one) or necessarily even
 their target's [[Prototype]] to perform lookup of inherited properties.
  They can implement inheritance in come completely different manner and
 using any internal state they want. The only way I can imagine generalizing
 what you are describing is to call the [[SetPrototypeOf]] MOP operation on
 the object and even then there is no general guarantee that the request
 would be accepted or that it would do what you are imagining.

 Allen





 On Wed, Oct 16, 2013 at 3:54 AM, Anne van Kesteren ann...@annevk.nlwrote:

 I believe last time this came up here some people hard concerns so I
 was wondering whether that was still the case and what alternatives
 there might be.

 In https://www.w3.org/Bugs/Public/show_bug.cgi?id=20567 we're
 considering to define the behavior Gecko exhibits when moving a node
 between trees in different global objects.

 Event handlers and custom elements make this somewhat more tricky and
 we're discussion how to work with them in the bug.

 The reason we want to change prototypes is to reduce the potential for
 memory leaks and give consistent behavior across nodes in a tree. I.e.
 they'll always be from the same global.

 (There's also the more complicated document.open() scenario, which we
 should discuss separately at some point I think, but for those trying
 to figure out how to define multiple realms in ECMAScript that's worth
 looking into.)


 --
 http://annevankesteren.nl/
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss




 --
 Cheers,
 --MarkM
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss



 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxying built-ins (Was: [[Invoke]] and implicit method calls)

2013-09-26 Thread Tom Van Cutsem
2013/9/25 Boris Zbarsky bzbar...@mit.edu

 On 9/25/13 3:47 PM, Mark S. Miller wrote:

 Hi Boris, I don't understand what you mean by in general. I think the
 SpiderMonkey use of cross-realm membranes is a great use case for
 membranes, and I don't understand why they need any special logic at all
 -- beyond the logic expressed by their handlers, which must include
 revocation.


 Mark,

 The issue is that if I have access to a different-realm Location object
 called loc, say, then:

   Object.**getOwnPropertyDescriptor(**Location.prototype,
 href).get.call(loc)

 should throw if the loc is not same-origin with me.  But:

 Object.**getOwnPropertyDescriptor(**Location.prototype,
 href).set.call(loc, whatever)

 should perform the set.  (There are actually some more complications here
 for the specific case of Location, but let's ignore them for now.)

 What that means in practice is that the membrane isn't actually revoked:
 it needs to be unwrapped to the real underlying object in some cases, but
 not others.

 The way we implement that, again, is with a way to unconditionally unwrap
 a cross-realm membrane, and a way to ask a cross-realm membrane whether
 it's ok to unwrap it.  Some of the methods/getters/setters involved use the
 former, and some use the latter.

 Note that in this case the actual property getter/setter is gotten without
 any interaction with membranes at all.  The only question is when a
 membrane around the thisArg to a function can be pierced to get to the
 thing the function actually knows how to operate on.


I believe the crucial part of why this works is because the built-ins can
recognize trusted, cross-realm proxies, from arbitrary other proxies.

In general, we can't let the built-in transfer control to an arbitrary
proxy handler, because users calling |builtin.call(thing)| don't expect
|thing| to influence the result of the call (cf. the discussion in the
[[invoke]] thread 
http://esdiscuss.org/topic/invoke-and-implicit-method-calls#content-115).

Answering MarkM's question of whether we can self-host such behavior, I
believe we can:

```js
var trustedMembraneProxies = new WeakMap(); // maps trusted membrane
proxies to their target, allowing code with access to this WeakMap to
unwrap them

Object.defineProperty(Location.prototype, href, {
   get: function() {
 var target = trustedMembraneProxies.get(this);
 if (target === undefined) {
// this-binding was not a cross-realm wrapper, just operate on the
original this-binding
target = this;
 }
 ... // execute builtin behavior with target as the this-binding
  }
}
```
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Removing Proxy hasOwn() trap (Was: [[Invoke]] and implicit method calls)

2013-09-25 Thread Tom Van Cutsem
I recall that Allen and I had previously agreed that it would be cleanest
if each of the [[internal]] methods on Object would correspond 1-to-1 to a
trap in the Proxy API (and I believe this is the case for the current ES6
draft).

So my stance is that we should either remove both hasOwn() and
[[HasOwnProperty]], or else remove neither.

I'm fine either way, but I believe Jason is right that [[HasOwnProperty]]
can be refactored as an abstract operation without any perf implications on
non-proxy objects.



2013/9/24 Jason Orendorff jason.orendo...@gmail.com

 Allen Wirfs-Brock al...@wirfs-brock.com wrote:
  On Sep 24, 2013, at 12:15 PM, André Bargull wrote:
  On Tue, Sep 24, 2013 at 2:34 PM, Allen Wirfs-Brock 
 al...@wirfs-brock.com wrote:
  I pretty sure we discussed this before and decided we wanted to
  keep [[HasOwnProperty]]. However, the only reason I can think of
  for doing so now is to avoid forcing exotic objects to allocated the
  property descriptors that [[GetOwnProperty]] produces.
 
  Exotic string and integer indexed objects ( = TypedArray instances)
 provide
  custom implementations for [[HasOwnProperty]] for exactly this reason.
 
  And because of proxies, a specified call  to  [[GetOwnProperty]] can't be
  optimized away unless you're sure you are dealing with an ordinary
 object.

 Here are three ways implementations can avoid this allocation.

 1. We are usually sure we’re dealing with an ordinary object! The only
 performance-sensitive call site is in [[HasProperty]] for ordinary
 objects, and there it is of course given that O is ordinary. An
 implementation can easily avoid the allocation in this case.

 2. In *all* HasOwnProperty call sites, the object will normally be
 ordinary. Implementations can optimize for that case using the same
 techniques they already use for everything else in the language.

 3. An implementation can certainly have an Object::hasOwnProperty
 virtual method, if it’s faster, even if the spec calls it an abstract
 operation rather than an internal method. Proxy::hasOwnProperty would
 have to call the getOwnPropertyDescriptor trap; all other
 implementations could avoid the allocation.

 I hope my point here is clear. There’s no performance reason to retain
 the .hasOwn trap or [[HasOwnProperty]].

 -j
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-25 Thread Tom Van Cutsem
2013/9/24 Brandon Benvie bben...@mozilla.com

 It seems unfortunate that we have to rely on a membrane for something as
 simply as `new Proxy(new Date, {}).getDate()` to work. [[Invoke]] as
 currently specced gets us somewhere at least.


You don't necessarily need a full membrane if you want that specific call
to work. If a proxy's get trap just returns a bound-function (with |this|
bound to target), this will work fine. I would postulate that this solution
easily covers the 90% case. Yes, methods can be objects with properties in
JS, and bound functions won't proxy those, but that isn't the common case.

JS programmers have been using function-wrappers since forever (including
bound functions since ES5). Bound functions aren't perfect forwarding
wrappers either. People seem to cope.

Perfect is the enemy of the good and all that ;-)
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-25 Thread Tom Van Cutsem
2013/9/24 Brendan Eich bren...@mozilla.com

 Brandon Benvie mailto:bben...@mozilla.com
 September 24, 2013 11:44 AM

 It seems unfortunate that we have to rely on a membrane for something as
 simply as `new Proxy(new Date, {}).getDate()` to work. [[Invoke]] as
 currently specced gets us somewhere at least.


 Somewhere half-right and half-wrong, depending on target object details
 over which a single trap cannot hope to abstract, is still half-wrong.
 Membranes based on built-in libraries should be easy enough to use.

 That does mean we have to get the built-in libraries right. Something best
 done on github (see promises), but then potentially absorbed by the spec in
 short order (whichever spec is in the right rapid-er release stage to
 absorb the library).

 Tom, are you happy with the state of the proxy-supporting libraries for
 ES6?


I presume by proxy-supporting libraries, you primarily mean the Handler
hierarchy at 
http://wiki.ecmascript.org/doku.php?id=harmony:virtual_object_api.

I have mixed feelings. It's all technically sound w.r.t. the spec, but I
have the feeling the proposed handlers are still too generic because they
are not driven by concrete use cases.

This is a part of the Proxy API that we could consider postponing beyond
ES6, encouraging the community to come up with their own abstractions.

Experimentation should be easy enough: this is all library code, easily
self-hosted. Here's my prototype implementation on GitHub: 
https://github.com/tvcutsem/harmony-reflect/blob/master/handlers.js.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-25 Thread Tom Van Cutsem
2013/9/25 Till Schneidereit t...@tillschneidereit.net

 Note that .invoke is not in that part, though: once proxies ship (in more
 than one browser) with all method calls invoking the .get handler, that
 ship has sailed. Suddenly not invoking the .get handler, anymore, will
 break applications.


Unless we add the trap with a default logic of calling the get trap when
no invoke trap is present on the handler. That would be deviating from
the current default behavior, but it would be possible.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-24 Thread Tom Van Cutsem
2013/9/23 Allen Wirfs-Brock al...@wirfs-brock.com


 On Sep 23, 2013, at 1:29 AM, Tom Van Cutsem wrote:

 I'm willing to consider changing the behavior of ForwardingHandler.get to
 auto-wrap functions and re-bind their this-value. I think you may be right
 that for users subclassing ForwardingHandler, they probably want the
 this-rebinding to happen for them by default.


 I think you should try to define it since you are arguing that such
 warppering is the solution.  However, as I described above, I don't think
 you can define a sufficiently generic wrappering semantics.


You are right. I accepted your challenge and started thinking about how to
wrap the method in the get trap.

The most trivial solution is to just wrap every target function in a bound
function, like so:

get: function(target, name, receiver) {
  var prop = target[name];
  if (typeof prop === function) { return prop.bind(target); }
  return prop;
}

However, functions are objects so may have properties. The bound function
would not expose the properties of its wrapped function. Gratuitous
wrapping also breaks identity if code depends on the identity of a
function. And the direct proxy would even throw a TypeError if the target's
property is non-configurable non-writable.

To solve all of that, you'd need proper membranes. But using membranes to
fix the this-rebinding problem seems like total overkill.

So forget ForwardingHandler.get doing auto-wrapping. The generic solution
is membranes. Anything else needs application-specific consideration.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-24 Thread Tom Van Cutsem
2013/9/24 Mark S. Miller erig...@google.com

 Ok, I've only been skimming the thread but I obviously missed something
 crucial. How would

 f.call(obj)

 cause obj's handler to be invoked at all, much less be given access to f?
 And why?


This is exactly the hazard I alluded to in earlier mails. Thanks to Kevin
for the more tangible example, and to André for the accurate summary.

It seems we are faced with the following dilemma:

1) There is code in the wild of the form:

var f = obj.method;
// later:
f.call(obj);

If obj is a transparent forwarding proxy, the expectation is for this call
to work. Here is a call that is *intended* to be polymorphic, but because
of funarg extraction, loses the intended polymorphism. [[InvokeFunction]]
would fix this.

2) There is code in the wild of the form:

var f = /* some closely held function, or an original built-in known only
to work on objects of a certain type */
// later:
f.call(obj);

The expectation of this code is that the f function is called (and only its
code runs), regardless of whether obj is a proxy or not. In particular, if
obj is a proxy, we do not want to transfer control to the proxy, and we
most certainly don't want to expose f to the proxy. This code *really*
means to make a non-polymorphic function call.

Both pieces of code are using Function.prototype.call, with opposite
expectations. Obviously we cannot fix both. The status-quo breaks pattern
#1 but keeps pattern #2 intact.

Reflect.apply is indeed the new [[Call]] but only addresses the issue
after the fact. Can we break pattern #2?

I believe Caja uses pattern #2 but MarkM or someone else from the Caja team
should confirm.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Removing Proxy hasOwn() trap (Was: [[Invoke]] and implicit method calls)

2013-09-24 Thread Tom Van Cutsem
[forking from [[invoke]]-thread for clarity]

2013/9/23 Jason Orendorff jason.orendo...@gmail.com

 On Mon, Sep 23, 2013 at 3:40 AM, Tom Van Cutsem tomvc...@gmail.com
 wrote:
  To me hasOwn() is as much a primitive as e.g. Object.keys().
 
  The only odd thing about it is that it lives on Object.prototype rather
 than
  as a static method on Object.
 
  I don't see the inconsistency, unless you would also want to remove
  Object.keys() because it can be expressed in terms of gOPN + gOPD.

 But Tom, there already is no trap for Object.keys()! It's specified in
 terms of [[OwnPropertyKeys]] and [[GetOwnProperty]].


My bad. I was still looking at the wiki page, which is outdated in that
respect.

Given the Object.keys precedent, we could consider removing hasOwn() and
re-specifying it in terms of getOwnPropertyDescriptor() !== undefined.

More object allocation, but the same holds true for removing the keys
trap.

Allen: would the removal of the hasOwn() trap imply that we can drop the
[[HasOwnProperty]] internal method altogether?

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-23 Thread Tom Van Cutsem
2013/9/21 Allen Wirfs-Brock al...@wirfs-brock.com


 On Sep 21, 2013, at 2:51 AM, Tom Van Cutsem wrote:

 2013/9/20 Allen Wirfs-Brock al...@wirfs-brock.com

 BTW, I would want to use  [[InvokeFunction]] for both directly
 obj.method() and in the internals of F.p.call/apply


 As I mentioned to your reply at the time, I believe the latter would break
 the expectations of existing code.


 There is an even stronger expectation among existing code that
obj.m()
 is equivalent to
var f=obj.m; f.call(obj)
 with the possibility of other computation being inserted between
 initializing f and calling it.

 More concretely, existing code expects that
 obj.valueOf()
 is equivalent to
 obj.valueOf.call()

 but if obj is a transparent forwarding proxy on a map instance (or most
 other built-ins) the first form will work as expected and the second form
 will throw unless something like [[InvokeFunction]] is used within F.p.call.


Or if obj is a transparent forwarding proxy done right, i.e. whose get
trap returns a wrapper function that re-binds |this| and then forwards (a
membrane does this automatically).



 The re-specification of call/apply in terms of [[InvokeFunction]] would be
 semantically identical to the current specification in all cases where the
 passed this value is not a Proxy. (or  some other exotic object that
 redefined [[InvokeFuntion]])

 Using [[InvokeFunction]] within F.p.call/apply would still retain their
 existing behavior for all normal situations where the this value is not a
 Proxy, so there would be no observable difference for existing code that is
 not designed to deal with proxies. Plus that existing code would continue
 to observe the obj.m() :: obj.m.call(m) equivalnce even when obj is a Proxy.



 Code that uses F.p.call/apply to apply a function it acquired through
 manual lookup typically expects it's going to execute the original
 behavior, and nothing else:

 var original_push = Array.prototype.push;
 ...
 original_push.call(unknownObject, ...args); // programmer expects this to
 either do the specced push() behavior or throw a TypeError (assuming
 original definition of 'call')


 Using this specific example, you are saying the programmer expects the
 above to throw if unknownObject is a transparently forwarding proxy over an
 Array instance.  I doubt if that is the actual expectation.  I think the
 expectation is that the orginal_push will be invoked as if was the function
 retrieved via unknownObject.push.   In other words, it is not trying to
 change the normal this binding semantics of obj.push(), it is only trying
 to force a local bind of obj.push to a specific value (ie, circumvent
 obj.[[Get]](push)).


Given that Array.isArray(proxyForArray) is specced to return false, I don't
see why the above code should work transparently on proxies-for-arrays,
while a simple Array.isArray test would fail.



 I'm skeptical that there are many (any?) existing situations where
 F.o.call/apply is used with the failure expectation WRT transparent proxies
 that is implicit in your example. Do you know of any?

 For situations that really want to do a naked [[Call]] without any
 proxy-based intercession the way to do it would be
 Reflect.call(original_push,unknownObject,...args) rather than
 original_push.call.(unknownObject,...args).


Indeed, except that I expressed concerns about the expectations of existing
ES5 code, for which it is too late to opt-in to the new Reflect.apply
primitive.


 JS fundamentally decouples property lookup from method call and thus has
 the ability to express non-polymorphic function calls. We shouldn't
 virtualize [[Call]].


 Are you suggesting that we should not have a Proxy apply trap?


No, not at all. For proxies that represent/wrap functions, it's necessary
to virtualize [[Call]].

My argument is that we should leave the [[Call]] behavior of *ordinary
functions* alone.

Re-specifying Function.prototype.{apply,call} in terms of a new
[[InvokeFunction]] MOP would mean that proxies can intercept the call
behavior of ordinary functions.



 But, more to your point, the existence of the this argument to call/apply
 means that they are inherently polymorphic calls in the sense you are
 talking about.  If the author of a function doesn't want it to be
 polymorphic on its this value then they should not write any references to
 |this|.

 If a proxy wants to intercept method calls, it can return a wrapper
 function from its get trap and override invoke. I'm pretty sure
 virtualizing [[Call]] will be a bridge too far.


 If this is the solution, then ForwardingHandler should do exactly that
 within its default get trap.  However, that is going to also be wrong
 some of the time.  You can't generically say that all [[Get]]'s that return
 a function value can replace that value with some other function and not
 expect to break something.


Absolutely. Proxies enable many different possible wrappers. There is no
one true way of building wrappers, so

Re: [[Invoke]] and implicit method calls

2013-09-23 Thread Tom Van Cutsem
2013/9/21 Allen Wirfs-Brock al...@wirfs-brock.com


 On Sep 21, 2013, at 2:53 AM, Tom Van Cutsem wrote:


 2013/9/21 Allen Wirfs-Brock al...@wirfs-brock.com


 On Sep 20, 2013, at 5:31 PM, Brendan Eich wrote:
   Given this, having the legacy internal calls continue to use get+call
 seems fine to me. A proxy implementing toString, e.g., can make it work
 using these traps just as well as via get+invoke, and without double lookup
 or boolean-trap-smelling (id | func) parameterization of invoke.

 In that case,  why not just use [[Get]]+[[InvokeFunction]] in all cases
 (including obj.m(()) and not have the current [[Invoke]] at all.  It allows
 the proxy handler to correctly intercede on all method invocations
 including conditional cones.


 Yes, except:

 a) proxies must then still allocate a temporary function object in the get
 trap. Thus, the primary reason for having a derived trap (less
 allocations), disappears.


 ??? Not in the normal cases where function already exist for the method
 properties.  They would only have to be allocated for the more exceptional
 situation where the handler is trying to directly implemented method
 behavior within the handler (via a switch statement, etc)

 or was there something else you had in mind with the above assertion?


I was thinking primarily about virtual object use-cases, where the method
properties don't necessarily already exist as functions.

But also membranes, for instance. A membrane must make sure no direct
reference to the method leaks to the caller, and thus must return a wrapper
from the get trap regardless of whether we include invokeFunction.



 b) every method call on a proxy triggers at least 2 traps (get +
 invoke). Another selling point of invoke() was that method calls go
 through one trap only.


 Yes, we do have the added overhead, of two traps but with the benefit is
 that we get a more consistent semantics that is a better match to current
 ES expectations.

 If we really are worried about the overhead of two traps we could have a
 derived invoke trap that does get+invokeFunction but I'm not sure the
 complexity is worth it (or that there would actually be any saving, isn't
 the the default implementation of invoke just going to essentially
 trigger the other two traps?)

 c) double-lifting needs 2 traps (get + invoke) rather than just get.


 I don't think so, using [[invokeFunction]] instead of [[Invoke]]
 eliminates the need for two:

 the current dispatch mechanism for Proxy Mop operations is essentially
 let trap = handler.[[Get]](handlerName);
 ...
 trap.[[Call]](handler,args);

 if [[InvokeFunction]] was available this would become

 let trap = handler.[[Get]](handlerName);
 ...
 handler.[[InvokeFunction]](trap, handler,args);

 The default behavior of [[InvokeFunction]] on a Proxy that does not have a
 corresponding invokeFunction trap defined is equivalent to a [[Call]] of
 the passed function so the behavior would be exactly the same.  All the
 metameta handler needs to define is get.


Ok, I stand corrected. But that default behavior surprised me. The default
behavior of all other traps is to forward the intercepted operation to the
target. The way you describe things, this would not be true of
invokeFunction.



 At that point, we're better off dropping [[InvokeFunction]] entirely.

 As Brendan mentioned, methods are extractable in JS. A new MOP operation
 doesn't relieve proxies from honoring that contract.


 It still appears to me that [[Get]]+[[InvokeFunction]] and respec'ing
 F.p.call/apply in terms of [[InvokeFunction]] is the closest semantic match
 to this expected behavior plus has the least anomalies WRT transparent
 proxying of built-ins with private state (and user defined classes that we
 WeakMaps for private state).


Except that respec'ing F.p.call/apply changes the [[Call]] behavior of
existing non-proxy functions. Am I the only one to think this is
potentially a serious hazard?



 I believe we made the right trade-offs so far and still stand by the
 status-quo.


 Which status-quo?  We have some fundamental semantic consistency issues
 involving Proxies and method invocation.

 We have a number of alternatives that have been discussed and they all
 seem to have both pros and cons associated with them. I also believe that
 done of them perfectly resolves all of the semantic consistency issues and
 at the same time preserves perfect actual or conceptual backwards
 compatibility.  Personally, I'm finding it difficult to remember all of the
 various pros and cons that we have individually discussed for each
 alternative.  I suspect we need to put together a side-by-side for each
 alternative so we can compare them.


Indeed, there are trade-offs and there is no silver bullet.

The status-quo, which I advocated, entails:

- we keep the invoke() trap, with its current signature: invoke(target,
propertyName, argsArray, receiver)
- conditional method calls in the spec are still expressed

Re: [[Invoke]] and implicit method calls

2013-09-23 Thread Tom Van Cutsem
2013/9/22 Jason Orendorff jason.orendo...@gmail.com

 On Fri, Sep 20, 2013 at 6:27 PM, Brandon Benvie bben...@mozilla.com
 wrote:
  Actually, taking the precedent of removing getPropertyDescriptor, it's
  has that would be removed.

 I think the logic of the current design is: primitives we keep;
 high-level operations that correspond to everyday syntax built into
 the language from of old (get/set/has/enumerate), we keep. But
 .hasOwn, like .getPropertyDescriptor, is neither.


To me hasOwn() is as much a primitive as e.g. Object.keys().

The only odd thing about it is that it lives on Object.prototype rather
than as a static method on Object.

I don't see the inconsistency, unless you would also want to remove
Object.keys() because it can be expressed in terms of gOPN + gOPD.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-21 Thread Tom Van Cutsem
2013/9/20 Allen Wirfs-Brock al...@wirfs-brock.com

 BTW, I would want to use  [[InvokeFunction]] for both directly
 obj.method() and in the internals of F.p.call/apply


As I mentioned to your reply at the time, I believe the latter would break
the expectations of existing code.

Code that uses F.p.call/apply to apply a function it acquired through
manual lookup typically expects it's going to execute the original
behavior, and nothing else:

var original_push = Array.prototype.push;
...
original_push.call(unknownObject, ...args); // programmer expects this to
either do the specced push() behavior or throw a TypeError (assuming
original definition of 'call')

JS fundamentally decouples property lookup from method call and thus has
the ability to express non-polymorphic function calls. We shouldn't
virtualize [[Call]]. If a proxy wants to intercept method calls, it can
return a wrapper function from its get trap and override invoke. I'm
pretty sure virtualizing [[Call]] will be a bridge too far.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: [[Invoke]] and implicit method calls

2013-09-21 Thread Tom Van Cutsem
2013/9/21 Allen Wirfs-Brock al...@wirfs-brock.com


 On Sep 20, 2013, at 4:27 PM, Brandon Benvie wrote:

 On 9/20/2013 12:19 PM, Jason Orendorff wrote:

 I think .hasOwn() should be removed.


 Actually, taking the precedent of removing getPropertyDescriptor, it's
 has that would be removed. The implementation of [[Has]] can easily walk
 the [[GetPrototype]] chain calling hasOwn on each until true or
 [[GetPrototype]] returns null. In fact, some agreed for a short time to
 *remove* the has trap specifically for this reason, but it was added back.

 https://mail.mozilla.org/pipermail/es-discuss/2012-November/026274.html


 [[Get]] and [[Set]] enable an exotic object to define its own property
 lookup semantics that isn't necessary the same as a simple follow the
 [[Prototype]] chain until a matching own property is found.  For example,
 they could use some sort of multiple inheritance resolution algorithm.
 [[HasProperty]] is needed to allow an external client to check for the
 existence of a property using the same algorithm as [[Get]] and [[Set]].


Indeed, we decided in favor of keeping has() for the reasons Allen stated:
so that proxies can virtualize the proto-chain-walk consistently for
property access (get/set) as well as property lookup (in-operator), and
enumeration (for-in loop).

Put another way: with only the fundamental traps, all proto-chain-walking
happens external to the proxy, so the proxy cannot virtualize it.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


  1   2   3   4   5   6   >