Re: Intercepting sets on array-like objects

2017-06-09 Thread Adam Klein
On Thu, Jun 8, 2017 at 11:32 AM, Tab Atkins Jr. 
wrote:

> Heya!  As part of designing the CSS Typed OM
> , we've ended up with at
> three (so far) places where we want an interface that represents a
> list of values:
>
> * CSSUnparsedValue
> ,
> representing alternating unparsed strings and variable references in a
> property
> * CSSNumericArray
> ,
> representing the n-ary arguments of sum/product/min/max operations
> * CSSTransformValue
> ,
> representing a list of transform functions
>
> The most natural way to represent these is as an Array, so authors can
> get all the Array methods, use `val[i]` syntax, etc.  However, doing
> so means we lose the ability to type-check sets to the values.
>
> In general, type-checking is an important part of APIs defined in
> WebIDL.  Any set to a property on an object is automatically
> type-checked, any arguments to methods are automatically type-checked,
> etc.  By building this into WebIDL, it removes the need for a lot of
> annoying boilerplate on the part of spec authors, and more
> importantly, removes the possibility that spec authors will forget to
> typecheck at all, or will typecheck in incorrect or weird bespoke
> ways.  Every API responds in exactly the same way when you pass the
> wrong type of object, and that's a Good Thing for both users and
> implementors.
>
> And so, it would be great to have the same ability to typecheck these
> Array-likes in the Typed OM.
>
> Naively, this requires a Proxy, so we can intercept uses of the []
> syntax.  However, we don't need all the rest of the Proxy
> functionality, just this one intercept - a setter function, just for
> `obj[foo]` rather than `obj.foo`.  Further, Typed Arrays already have
> *precisely* the functionality I'd like to use - they intercept setting
> using [], and convert it into the appropriate type of number.  AWB
> also proposed adding exactly this hook in the past (I think it was
> called "Array reformation" or something?).
>
> Thoughts?
>
> Note that if we don't get some variant of this functionality, these
> APIs will instead do one of:
>
> * just using Proxies (already defined in WebIDL)
>

When you say "Proxies" here, I believe you're referring to the "indexed
properties" feature of WebIDL (
https://heycam.github.io/webidl/#idl-indexed-properties). This seems like
the right mechanism to use, from a WebIDL spec, to get the behavior you
desire. In Chromium/V8, this doesn't actually use Proxies under the hood
(we have something called "indexed property handlers", see the API at
https://cs.chromium.org/chromium/src/v8/include/v8.h?rcl=ff98ddca4a1770c2868d44f1cdfe1d4656363f30=5781),
but it's definitely implementable using Proxies.

- Adam


> * using .get()/.set() functions with integer arguments to badly emulate
> arrays
> * just relying on iterator/constructor, so users have to convert the
> object to an Array, fiddle with it, then construct a brand new object
>
> And whichever I end up with, I'll be advocating that as the Standard
> WebIDL Way to do array-likes, so we can finally have some consistency.
>
> ~TJ
> ___
> 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: getOwnPropertyDescriptor side effects

2017-01-06 Thread Adam Klein
With the advent of Proxy in ES2015, getOwnPropertyDescriptor can always
have side-effects:

Object.getOwnPropertyDescriptor(new Proxy({}, { getOwnPropertyDescriptor()
{ throw "hello world" } }), "foo")

On Fri, Jan 6, 2017 at 11:11 AM, Francisco Tolmasky 
wrote:

> Is there any position on whether getOwnPropertyDescriptor should not have
> side-effects? I ask because some v8 getOwnPropertyDescriptor *do* have side
> effects (for example, Object.getOwnPropertyDescriptor(new Error, “stack”)
> will call Error.prepareStackTrace (it used to not)). Currently I
> treat getOwnPropertyDescriptor as a “safe” way to observe an object —
> (unlike say calling each member on an object which could set off getters).
>
> --
> Francisco Tolmasky
> www.tolmasky.com
> tolma...@gmail.com
>
> ___
> 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: An update on Object.observe

2015-11-03 Thread Adam Klein
On Tue, Nov 3, 2015 at 1:25 PM, Coroutines <corouti...@gmail.com> wrote:

> On Tue, Nov 3, 2015 at 1:24 PM, Adam Klein <ad...@chromium.org> wrote:
>
> > Note that O.o didn't help for the "as they happen" case anyway, as
> callbacks
> > were delayed until the end of the turn (same timing as Promise
> resolution).
> > Proxies are required to do synchronous interception.
>
> Would this be similar to .nextTick() in node?  I would still view this
> as much better than polling for changes with a timer :>


Yes, similar to nextTick() (and I agree that's better than polling,
conceptually). But Proxies are strictly more powerful.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: An update on Object.observe

2015-11-03 Thread Adam Klein
On Tue, Nov 3, 2015 at 1:18 PM, Coroutines  wrote:

> On Tue, Nov 3, 2015 at 3:26 AM, Alexander Jones  wrote:
> > In my opinion, the fundamental record type we build our JS on should be
> > getting dumber, not smarter. It feels inappropriate to be piling more
> > difficult-to-reason-about mechanisms on top before reeling in exotic host
> > objects. With Proxy out of the bag, I'm not so hopeful for the humble
> Object
> > anymore.
>
> As far as I know, without Proxy or Object.observe() there would be no
> possible way to watch for changes *as they happen* and directly fire
> off an observing function or handler.  You need assistance from the JS
> runtime to track stuff like this correctly and efficiently.  The
> polyfills for O.o() use timers to watch for changes - changes/accesses
> can be missed between polls.  I am happy Proxy is at least staying
> around - I was initially freaking out thinking Object.observe() was
> the mechanism behind Proxy's magicalness.


Note that O.o didn't help for the "as they happen" case anyway, as
callbacks were delayed until the end of the turn (same timing as Promise
resolution). Proxies are required to do synchronous interception.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


An update on Object.observe

2015-11-02 Thread Adam Klein
Over three years ago, Rafael Weinstein, Erik Arvidsson, and I set out to
design and implement what we believed to be the primitive underlying the
data-binding system of MDV ("model-driven views"). We prototyped an
implementation in a branch of V8, then got agreement from the V8 team to
build a real version upstream, while pushing Object.observe ("O.o") as a
part of the upcoming ES7 standard and working with the Polymer team to
build their data-binding system on top of O.o.

Three years later, the world has changed in a variety of ways. While other
data-binding frameworks (such as Ember and Angular) showed interest, it was
difficult to see how they could evolve their existing model to match that
of O.o. Polymer rewrote from the ground up for its 1.0 release, and in that
rebuilding did not utilize O.o. And React's processing model, which tries
to avoid the mutable state inherent in data-binding systems, has become
quite popular on the web.

After much discussion with the parties involved, I plan to withdraw the
Object.observe proposal from TC39 (where it currently sits at stage 2 in
the ES spec process), and hope to remove support from V8 by the end of the
year (the feature is used on 0.0169% of Chrome pageviews, according to
chromestatus.com).

For developers who have been experimenting with O.o and are seeking a
transition path, consider using a polyfill such as
https://github.com/MaxArt2501/object-observe or a wrapper library like
https://github.com/polymer/observe-js.

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


Re: An update on Object.observe

2015-11-02 Thread Adam Klein
On Mon, Nov 2, 2015 at 11:21 AM, Matthew Phillips 
wrote:

>
> Over three years ago, Rafael Weinstein, Erik Arvidsson, and I set out to
>> design and implement what we believed to be the primitive underlying the
>> data-binding system of MDV ("model-driven views"). We prototyped an
>> implementation in a branch of V8, then got agreement from the V8 team to
>> build a real version upstream, while pushing Object.observe ("O.o") as a
>> part of the upcoming ES7 standard and working with the Polymer team to
>> build their data-binding system on top of O.o.
>>
>> Three years later, the world has changed in a variety of ways. While
>> other data-binding frameworks (such as Ember and Angular) showed interest,
>> it was difficult to see how they could evolve their existing model to match
>> that of O.o. Polymer rewrote from the ground up for its 1.0 release, and in
>> that rebuilding did not utilize O.o. And React's processing model, which
>> tries to avoid the mutable state inherent in data-binding systems, has
>> become quite popular on the web.
>>
>> After much discussion with the parties involved, I plan to withdraw the
>> Object.observe proposal from TC39 (where it currently sits at stage 2 in
>> the ES spec process), and hope to remove support from V8 by the end of the
>> year (the feature is used on 0.0169% of Chrome pageviews, according to
>> chromestatus.com).
>>
>> For developers who have been experimenting with O.o and are seeking a
>> transition path, consider using a polyfill such as
>> https://github.com/MaxArt2501/object-observe or a wrapper library like
>> https://github.com/polymer/observe-js.
>>
>> - Adam
>>
>
> What is Polymer using in place of Object.observe?
>

Polymer uses a mix of getters/setters and DOM events to handle data
propagation. Details can be found on polymer-project.org, e.g.:

https://www.polymer-project.org/1.0/docs/devguide/properties.html#change-callbacks
https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#change-notification-protocol
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Global lexical tier

2015-08-31 Thread Adam Klein
Note that this behavior in v8/Chrome is only about sloppy mode. In strict
mode, v8 implements the ES6 spec (and we'll likely have support for lexical
declarations in sloppy mode soon).

Though I personally agree that the top-level lexical scoping in ES6 seems
unfortunate.

On Mon, Aug 31, 2015 at 9:53 AM, Matthew Robb 
wrote:

> Personally I am a fan of Chrome's CURRENT solution:
> ```
> Uncaught SyntaxError: Block-scoped declarations (let, const, function,
> class) not yet supported outside strict mode
> ```
>
>
> - Matthew Robb
>
> On Mon, Aug 31, 2015 at 12:08 PM, Jason Orendorff <
> jason.orendo...@gmail.com> wrote:
>
>> Hi everyone. Can we talk about the global lexical tier?
>>
>> This was a mistake, a real blunder. We all should have known better.
>> An extensible intermediate scope implies dynamic scoping. The referent
>> of an identifier can change only once, but it can change. It's like an
>> implicit `with` block around *all code*.
>>
>> This pattern for declaring variable in multiple scripts won't work
>> with let/const:
>>
>> var MyES3Module = MyES3Module || {};
>>
>> There's no workaround except "keep using var".
>>
>> It's now possible to get a binding permanently wedged, which is bad for a
>> REPL:
>>
>> js> let z = Maht.PI;  // oops, typo
>> ReferenceError: Maht is not defined
>> js> z
>> ReferenceError: binding is not initialized: "z"
>> js> z = 1;
>> ReferenceError: binding is not initialized: "z"
>> js> delete z;
>> false
>> js> let z = 1;
>> SyntaxError: redeclaration of variable: "z"
>>
>> For a single name to have two global bindings, both mutable, is
>> astonishing.
>>
>> All of this was unnecessary. What's the benefit to users? We ran
>> roughshod over existing practice, invariants, and expectations in
>> order to obtain a kind of self-consistency for `let` that users don't
>> expect or even care about.
>>
>> We should have just made toplevel let/const/class create global
>> properties, like var. This is how it was proposed originally and how
>> Babel implements it today. For SpiderMonkey, switching to the worse,
>> less user-friendly way without regressing performance is
>> time-consuming.
>>
>> We knew all this. We didn't evaluate it correctly. What we
>> particularly missed is that we already had modules as the way forward
>> to a nice toplevel lexical tier, and weird half measures for scripts
>> were pointless.
>>
>> -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: Property ordering of [[Enumerate]] / getOwnPropertyNames()

2015-08-20 Thread Adam Klein
This doesn't answer the spec question, exactly, but v8 doesn't currently
conform to ES6's requirements for [[OwnPropertyKeys]]: some objects return
names in an implementation-dependent order (see
https://code.google.com/p/v8/issues/detail?id=3056 for more details).

On Thu, Aug 20, 2015 at 9:54 AM, Jesse McCarthy 
es-discuss-2015...@jessemccarthy.net wrote:

 I just want to confirm some things about property enumeration order of
 plain Objects. I apologize that this has probably already been discussed
 before, but it's hard to locate a clear answer. Please note that I'm solely
 asking about ES2015 spec compliance, not what's in the wild.

 Given:

 ```js
 var y = Object.create(null);
 // Note that property names are all strings.
 y.one = 1;
 y.two = 2;
 y.three = 3;
 ```

 This is my understanding of what's guaranteed (or not) about enumeration
 order (in the context of the example given):

 1. No guarantee of order
 Anything that relies on or has property-order equivalence with
 `[[Enumerate]]` or `EnumerableOwnNames`
 1b. for (x in y)
 1c. Object.keys(y)

 This is based on the statement in 9.1.11 [[Enumerate]] () step 1:

 The mechanics and order of enumerating the properties is not specified


 Although it says that...

 [[Enumerate]] must obtain the own property keys of the target object as
 if by calling its [[OwnPropertyKeys]] internal method.


 ...and `[[OwnPropertyKeys]]` specifies ordering, my reading is that
 `[[Enumerate]]` doesn't guarantee that the iterator it returns will
 preserve the order returned by `[[OwnPropertyKeys]]`.

 2. Guarantee of insertion order (['one', 'two', 'three'])
 Object.getOwnPropertyNames(y)

 Are those interpretations correct?

 Related:
 In this thread...
 https://esdiscuss.org/topic/nailing-object-property-order

 ...Bergi asked these pertinent questions that no one answered:

 But why was the default object [[enumerate]] algorithm not specced to
 match the [[OwnPropertyKeys]] order then?
 ...
 Shouldn't we add a guarantee to [[enumerate]] that the subset of
 enumerated own properties comes in insertion order as well?


 This is partly in reference to http://stackoverflow.com/a/30244410/1034448

 ___
 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: Re-exporting imports and CreateImportBinding assertions

2015-04-06 Thread Adam Klein
And to close the loop: rev37 makes clear that ResolveExport() will follow
re-exported import bindings to discover the module in which they
originated. This makes all the assertions correct. In my example, it means
that the CreateImportBinding call in 'a' is:

CreateImportBinding(x, 'c', x)

Thanks to Allen for the swift turnaround of these changes.

On Thu, Apr 2, 2015 at 8:17 AM, Adam Klein ad...@chromium.org wrote:

 I've added this to a few bugs on the bug-tracker:

 https://bugs.ecmascript.org/show_bug.cgi?id=4184 (CreateImportBinding)
 https://bugs.ecmascript.org/show_bug.cgi?id=4244 (GetExportedNames and
 ResolveExport)

 On Wed, Apr 1, 2015 at 4:31 PM, Adam Klein ad...@chromium.org wrote:

 I have a question about CreateImportBinding(N, M, N2) (where N is the
 name to create in the importing module, and M is a module which exports N2).

 Step 4 of
 https://people.mozilla.org/~jorendorff/es6-draft.html#sec-createimportbinding
 is the following assertion

 Assert: When M.[[Environment]] is instantiated it will have a direct
 binding for N2.

 What about the case were M is simply re-exporting an import? Consider:

 -
 module 'a':

 import { x } from 'b';

 -
 module 'b':

 import { x } from 'c';
 export { x };

 -
 module 'c':

 export let x = 42;

 -

 In this case, when running CreateImportBinding(x, 'b', x) in module 'a',
 the assertion fails, as x in 'b' is an immutable indirect binding (itself
 created by CreateImportBinding).

 Is there a need for this assert I'm missing? I don't think skipping over
 this assert, or removing direct from its wording,  will cause any
 problems. Also, the term direct binding is not defined anywhere that I
 can find, except as the negation of the indirect binding created by
 CreateImportBinding.

 Note that there's a similar issue in ResolveExport: step 4.a.i of
 https://people.mozilla.org/~jorendorff/es6-draft.html#sec-resolveexport
 asserts that resolved exports found in [[LocalExportEntries]] are leaf
 bindings (another term that goes undefined), where by the usual CS
 definition of leaf the assertion would be false for x in 'b' (when
 resolved from 'a').

 - Adam



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


Re: Re-exporting imports and CreateImportBinding assertions

2015-04-02 Thread Adam Klein
I've added this to a few bugs on the bug-tracker:

https://bugs.ecmascript.org/show_bug.cgi?id=4184 (CreateImportBinding)
https://bugs.ecmascript.org/show_bug.cgi?id=4244 (GetExportedNames and
ResolveExport)

On Wed, Apr 1, 2015 at 4:31 PM, Adam Klein ad...@chromium.org wrote:

 I have a question about CreateImportBinding(N, M, N2) (where N is the name
 to create in the importing module, and M is a module which exports N2).

 Step 4 of
 https://people.mozilla.org/~jorendorff/es6-draft.html#sec-createimportbinding
 is the following assertion

 Assert: When M.[[Environment]] is instantiated it will have a direct
 binding for N2.

 What about the case were M is simply re-exporting an import? Consider:

 -
 module 'a':

 import { x } from 'b';

 -
 module 'b':

 import { x } from 'c';
 export { x };

 -
 module 'c':

 export let x = 42;

 -

 In this case, when running CreateImportBinding(x, 'b', x) in module 'a',
 the assertion fails, as x in 'b' is an immutable indirect binding (itself
 created by CreateImportBinding).

 Is there a need for this assert I'm missing? I don't think skipping over
 this assert, or removing direct from its wording,  will cause any
 problems. Also, the term direct binding is not defined anywhere that I
 can find, except as the negation of the indirect binding created by
 CreateImportBinding.

 Note that there's a similar issue in ResolveExport: step 4.a.i of
 https://people.mozilla.org/~jorendorff/es6-draft.html#sec-resolveexport
 asserts that resolved exports found in [[LocalExportEntries]] are leaf
 bindings (another term that goes undefined), where by the usual CS
 definition of leaf the assertion would be false for x in 'b' (when
 resolved from 'a').

 - Adam

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


Re-exporting imports and CreateImportBinding assertions

2015-04-01 Thread Adam Klein
I have a question about CreateImportBinding(N, M, N2) (where N is the name
to create in the importing module, and M is a module which exports N2).

Step 4 of
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-createimportbinding
is the following assertion

Assert: When M.[[Environment]] is instantiated it will have a direct
binding for N2.

What about the case were M is simply re-exporting an import? Consider:

-
module 'a':

import { x } from 'b';

-
module 'b':

import { x } from 'c';
export { x };

-
module 'c':

export let x = 42;

-

In this case, when running CreateImportBinding(x, 'b', x) in module 'a',
the assertion fails, as x in 'b' is an immutable indirect binding (itself
created by CreateImportBinding).

Is there a need for this assert I'm missing? I don't think skipping over
this assert, or removing direct from its wording,  will cause any
problems. Also, the term direct binding is not defined anywhere that I
can find, except as the negation of the indirect binding created by
CreateImportBinding.

Note that there's a similar issue in ResolveExport: step 4.a.i of
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-resolveexport
asserts that resolved exports found in [[LocalExportEntries]] are leaf
bindings (another term that goes undefined), where by the usual CS
definition of leaf the assertion would be false for x in 'b' (when
resolved from 'a').

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


Re: Very large array indices and unshift/splice

2014-10-27 Thread Adam Klein
On Mon, Oct 27, 2014 at 4:58 AM, Brendan Eich bren...@mozilla.org wrote:

 Allen Wirfs-Brock wrote:

 Arguably a design bug, rather than a spec. bug.  But I'm assuming that
 who ever originally wrote up these algorithms were being intentional about
 such things.


 Design, vs. accidental. Spec, vs. implementation. Potato, Potahtoe :-P.

 I think we should fix 'em as we find them, if implementations do not agree
 (and they don't usefully agree here).


For what it's worth, given that there exists one implementation (IE 11)
that gets this right per spec, I'm more inclined as an implementor to match
that than to try to get the spec changed here. I think Allen and Domenic
answered my question about why this isn't a precondition when they pointed
out that ToLength() is now greater than the max array length.

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


Very large array indices and unshift/splice

2014-10-23 Thread Adam Klein
Consider the following snippet, along with the spec for
Array.prototype.unshift (
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.unshift
):

var arr = [];
arr[0xfffe] = 10;
try {
  arr.unshift(1);
} catch(e) {
  // e is a RangeError, since the unshift operation will try to set the
length to 0x
}

what should the state of arr be after this botched operation? The way the
spec is written, all the element manipulation happens before the RangeError
occurs, so arr[0x] should be 10 and arr[0xfffe] should have
been deleted.

But it's not clear this is worthwhile. I tested this in V8, SpiderMonkey,
and JSC.

V8 properly throws a range error, but fails to move the element up one
index.
SpiderMonkey hangs (presumably because it has no special logic to deal with
very large, sparse arrays).
JSC throws an Out of memory Error and also fails to move the element up
one index.

A similar thing happens if one attempts to splice items into the array.

Is there any reason not to specify some precondition checking in these
algorithms and spec them to throw the RangeError without interacting with
the elements of the array if it's known a priori that the resulting length
will be  2^32-1?

In V8 and JSC this nearly matches existing behavior.  In Firefox it would
cause a change in behavior, but any code depending on the existing behavior
would be hanging for a long time already.

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


Re: Event loops in navigated-away-from windows

2014-10-15 Thread Adam Klein
On Tue, Oct 14, 2014 at 7:50 PM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 9/26/14, 10:03 PM, Boris Zbarsky wrote:

 2)  Say someone runs this in a web page:

(function f() Promise.resolve().then(f))()

 what should happen when the user navigates away from that web page and
 why?


 Given the lack of response from other implementors, I guess we'll just
 implement whatever is simplest in Gecko for now...


Sorry for my delay in responding. Can you say what is simplest for Gecko in
this case? One of the reasons I didn't respond to the thread immediately is
that from my perspective Chromium has fairly ill-defined behavior for
navigated-away pages, due to the fact that they often die due to factors
that can't be explained by the platform (e.g., their host process dies). So
I'd be interested in what makes sense for Gecko and whether it might just
happen to be compatible with what we do in Chromium/Blink/V8.

Also, for case (1), is this all happening within one frame, or is this a
cross-frame example?

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