Intercepting sets on array-like objects

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Intercepting sets on array-like objects

Tab Atkins Jr.
Heya!  As part of designing the CSS Typed OM
<https://drafts.css-houdini.org/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
<https://drafts.css-houdini.org/css-typed-om/#unparsedvalue-objects>,
representing alternating unparsed strings and variable references in a
property
* CSSNumericArray
<https://drafts.css-houdini.org/css-typed-om/#cssnumericarray>,
representing the n-ary arguments of sum/product/min/max operations
* CSSTransformValue
<https://drafts.css-houdini.org/css-typed-om/#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)
* 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Intercepting sets on array-like objects

Mark S. Miller-2
Interesting. At https://github.com/tvcutsem/es-lab/issues/21 Tom and I have been discussing a way to make Proxies cheaper, and Proxies that only override a few traps and let the rest default, much cheaper.



On Thu, Jun 8, 2017 at 11:32 AM, Tab Atkins Jr. <[hidden email]> wrote:
Heya!  As part of designing the CSS Typed OM
<https://drafts.css-houdini.org/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
<https://drafts.css-houdini.org/css-typed-om/#unparsedvalue-objects>,
representing alternating unparsed strings and variable references in a
property
* CSSNumericArray
<https://drafts.css-houdini.org/css-typed-om/#cssnumericarray>,
representing the n-ary arguments of sum/product/min/max operations
* CSSTransformValue
<https://drafts.css-houdini.org/css-typed-om/#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)
* 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Intercepting sets on array-like objects

Allen Wirfs-Brock
In reply to this post by Tab Atkins Jr.

On Jun 8, 2017, at 11:32 AM, Tab Atkins Jr. <[hidden email]> wrote:

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?).


the basic idea was that distinct internal methods (Proxy traps) are used for . and [] property accesses and that the default behavior for [ ] accesses is to look for specific symbol-keyed methods and if found defer the access logic to the method.  If not found the behavior is the same as for . accesses.

Allen

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Intercepting sets on array-like objects

Adam Klein
In reply to this post by Tab Atkins Jr.
On Thu, Jun 8, 2017 at 11:32 AM, Tab Atkins Jr. <[hidden email]> wrote:
Heya!  As part of designing the CSS Typed OM
<https://drafts.css-houdini.org/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
<https://drafts.css-houdini.org/css-typed-om/#unparsedvalue-objects>,
representing alternating unparsed strings and variable references in a
property
* CSSNumericArray
<https://drafts.css-houdini.org/css-typed-om/#cssnumericarray>,
representing the n-ary arguments of sum/product/min/max operations
* CSSTransformValue
<https://drafts.css-houdini.org/css-typed-om/#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&l=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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Intercepting sets on array-like objects

Tab Atkins Jr.
On Fri, Jun 9, 2017 at 1:57 PM, Adam Klein <[hidden email]> wrote:

> On Thu, Jun 8, 2017 at 11:32 AM, Tab Atkins Jr. <[hidden email]>
> wrote:
>> 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&l=5781),
> but it's definitely implementable using Proxies.

Correct.

WebIDL's indexed getters/setters would fulfill my use-case *exactly*.
If that's okay to use, per TC39 consensus, then awesome!

However, in <https://github.com/heycam/webidl/issues/345#issuecomment-300734048>
Anne says:

> [When] we discussed those kind of approaches with TC39, they told us not
> to and to just use Array. It wasn't just about [], it was also about FileList,
> NodeList, etc. And the problem with those was not that they did not have
> enough methods like Array, it was that they required a proxy.

Thus my confusion/consternation.

If this is incorrect, and indexed getters/setters are indeed fine to
use in new APIs, then we can close this thread "no change" and I can
go away happy. ^_^

~TJ
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Intercepting sets on array-like objects

Domenic Denicola
I'm not really sure how you're expecting to get an answer "according to TC39." One member had replied and given his suggestion. I don't think it's a good one for new APIs; I think new APIs should use arrays and not type check on sets but at processing time. I'm sure there will be many other opinions from other TC39 members.



From: "Tab Atkins Jr." <[hidden email]>
Sent: Jun 9, 2017 5:02 PM
To: Adam Klein
Cc: es-discuss
Subject: Re: Intercepting sets on array-like objects

On Fri, Jun 9, 2017 at 1:57 PM, Adam Klein <[hidden email]> wrote:
> On Thu, Jun 8, 2017 at 11:32 AM, Tab Atkins Jr. <[hidden email]>
> wrote:
>> 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&l=5781),
> but it's definitely implementable using Proxies.

Correct.

WebIDL's indexed getters/setters would fulfill my use-case *exactly*.
If that's okay to use, per TC39 consensus, then awesome!

However, in <https://github.com/heycam/webidl/issues/345#issuecomment-300734048>
Anne says:

> [When] we discussed those kind of approaches with TC39, they told us not
> to and to just use Array. It wasn't just about [], it was also about FileList,
> NodeList, etc. And the problem with those was not that they did not have
> enough methods like Array, it was that they required a proxy.

Thus my confusion/consternation.

If this is incorrect, and indexed getters/setters are indeed fine to
use in new APIs, then we can close this thread "no change" and I can
go away happy. ^_^

~TJ
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Intercepting sets on array-like objects

Tab Atkins Jr.
On Fri, Jun 9, 2017 at 2:07 PM, Domenic Denicola <[hidden email]> wrote:
> I'm not really sure how you're expecting to get an answer "according to
> TC39."

I was told by Anne in
<https://github.com/heycam/webidl/issues/345#issuecomment-300734048>
to "go back to TC39 I suppose and say you really want to do typed
arrays again".  (And in messages preceding/following that, Anne
implies that his pushback on the idea is motivated by historical TC39
dislike for this approach.) I'm doing precisely that.

> One member had replied and given his suggestion. I don't think it's a
> good one for new APIs; I think new APIs should use arrays and not type check
> on sets but at processing time. I'm sure there will be many other opinions
> from other TC39 members.

"Don't type-check things that look like arrays" means carving out a
special one-off shape in web APIs - every single property set or
method call in WebIDL typechecks the values. What makes "things that
look like arrays" special in this regard?  I can't avoid typechecking
- why should specs have to do bespoke typechecking in their functions
that *accept* these object, versus every other type of object in the
platform that is automatically type-happy?

Drilling in deeper: *fixed length* "things that look like arrays" can
have type-checking in WebIDL no problem, you just have to define the
names in prose, due to a legacy limitation of the WebIDL syntax. This
allows users to do `obj[1] = val;` and get a TypeError thrown when it
mismatches, exactly like they'd get with `obj.foo = val`. What makes
fixed-length different from dynamic-length "things that look like an
array"?  There's no semantic/usability difference between these cases;
it's purely an accidental artifact of the particular way JS handles
the [] syntax.

This is not good API design. Platform objects can mimic every other JS
object; there's no user-understandable reason why they should be
different in this one particular case.

------------

Digging back a bit to try and find what TC39 opinion Anne was
referring to, I instead found this 2009 thread
<https://lists.w3.org/Archives/Public/public-webapps/2009JulSep/1346.html>
which might be what he is remembering (it mentions FileList and
DOMTokenList), where TC39 members were pretty uniformly supportive of
an "integer property catch-all" (explicitly suggested by Maciej in
<https://lists.w3.org/Archives/Public/public-webapps/2009JulSep/1354.html>)
so that platform APIs could do non-live Array-likes.

Did something change in the intervening 8 years? If so, what, and why?
 (This was the second result in my mail archives for "indexed getter",
so I don't think I'm cherrypicking this thread either.)

~TJ
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss