This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 22391 - Sequence or Array
Summary: Sequence or Array
Status: RESOLVED WORKSFORME
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: WebIDL (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Cameron McCormack
QA Contact: public-webapps-bugzilla
URL:
Whiteboard: [v1]
Keywords:
Depends on:
Blocks:
 
Reported: 2013-06-17 20:31 UTC by Marcos Caceres
Modified: 2016-09-08 20:56 UTC (History)
7 users (show)

See Also:


Attachments

Description Marcos Caceres 2013-06-17 20:31:19 UTC
The spec doesn't provide enough guidance as to when it's ok to use an array or when it's not ok (and when a sequence should be used instead... and vice versa). 

Seems I'm not the only one confused by this:
http://darobin.github.io/api-design-cookbook/#sequences-and-arrays
Comment 1 Anne 2013-07-10 19:44:57 UTC
http://wiki.whatwg.org/wiki/IDL

We should kill [] I think.

For attributes we could return a frozen array and replace the array with another frozen array if it needs to be updated.

What other patterns do we have?
Comment 2 Travis Leithead [MSFT] 2013-07-10 19:54:42 UTC
I think that [] was going to be able to replace all usages of *List or *Collection that are preexisting in the DOM (e.g., NodeList, HTMLCollection). 

Are you saying that it's better to just have specific interfaces that describe their specific behavior, than introduce a generic [] array-type that can handle all these scenarios?

My guidance to internal teams at Microsoft has always centered around when to return unique instances per call (use sequence) or singleton objects with mutating array contents (use [] or *List/*Collection, etc.).
Comment 3 Anne 2013-07-10 19:57:43 UTC
We should have something generic syntax-wise, but it should work around (frozen) JavaScript Array objects and not a new kind of IDL object (which is what [] is).
Comment 4 Boris Zbarsky 2013-07-10 20:02:41 UTC
[] as currently specified can't replace NodeList and HTMLCollection because those have methods other than [] and .length that are used in the wild...

Further, there seems to be a trend away from "live" lists (whether good or not).

For a non-live list, a JS Array (if a new copy) or frozen JS Array (if shared with other consumers) seems just fine.
Comment 5 Tab Atkins Jr. 2013-07-10 20:08:32 UTC
(In reply to comment #4)
> [] as currently specified can't replace NodeList and HTMLCollection because
> those have methods other than [] and .length that are used in the wild...

And live lists seem to tend to sprout new methods anyway, even if they initially have only [] and .length.

I'm down with killing type[] in favor of just using [ArrayClass] interfaces.

> For a non-live list, a JS Array (if a new copy) or frozen JS Array (if
> shared with other consumers) seems just fine.

Is the frozen-ness something that needs to be indicated in prose?
Comment 6 Boris Zbarsky 2013-07-10 20:09:23 UTC
> Is the frozen-ness something that needs to be indicated in prose?

I would vastly prefer we do it in IDL...
Comment 7 Domenic Denicola 2013-07-10 20:14:56 UTC
One thing to watch out for is to avoid situations where `myDOMThing.arrayProp !== myDOMThing.arrayProp`. This would occur if you specify properties as having getters that always return fresh arrays (or that return new, frozen arrays that represent mutable underlying data).

If you need a non-mutable view into data that could change over time, a method returning a (non-frozen, snapshot) array seems best to me.
Comment 8 Jonas Sicking (Not reading bugmail) 2013-07-10 20:20:48 UTC
(In reply to comment #5)
> I'm down with killing type[] in favor of just using [ArrayClass] interfaces.

The point would be to *not* introduce any interfaces at all. Whatever we'd use in the WebIDL, it would map to normal real JS Arrays.
Comment 9 Boris Zbarsky 2013-07-10 20:29:10 UTC
Domenic, I'm not sure what you mean by "non-frozen, snapshot".

Fundamentally, there are several kinds of APIs:

1)  API that just returns a new array each time.  These should return a sequence
    (which means just a normal writable JS Array) and should be methods, not
    property getters.
2)  API that keeps returning the same array object as long as its contents do not
    change.  This can be a method, of course (returning a frozen JS Array, say,
    so that one caller can't mess up what other callers see).  Can it be a
    property getter?  It seems like this is an OK thing to do, actually, since
    the new object would only appear when the list being represented has in fact
    changed.
3)  APIs that return some sort of live arraylike collection.  The problem here is
    that in most cases the liveness means that the DOM implementation needs to be
    able to write into the array but callers need to not be able to do so.  What
    that means is that the script-visible behavior is basically some sort of
    proxy around an Array.

As I said in comment 4, there has been a general movement away from case 3 in API design.  Case 1 is non-controversial.  So the main interesting thing is case 2.
Comment 10 Domenic Denicola 2013-07-10 20:52:07 UTC
(In reply to comment #9)
> Domenic, I'm not sure what you mean by "non-frozen, snapshot".

"Non-frozen" = normal writable JS array; "snapshot" = does not track the underlying mutable state, but instead gives you the elements that were available when you called the method. Basically I was talking about exactly your case 1.

> 2)  API that keeps returning the same array object as long as its contents do not change.  This can be a method, of course (returning a frozen JS Array, say, so that one caller can't mess up what other callers see).  Can it be a property getter?  It seems like this is an OK thing to do, actually, since the new object would only appear when the list being represented has in fact changed.

I think you're right; property getters are OK, at least if the returned array is frozen. It would be quite easy to implement such a property in JS using a getter that regenerates and caches an array if it detects a change in the underlying data. Put another way, this might be a natural pattern for ES5 developers who want to expose read-only views of mutable data to the outside world.

A method feels a bit more preferable, but probably just because I'm used to working with so much ES3 code. Specific use cases might be helpful in deciding whether we want to recommend methods or properties.

> 3)  APIs that return some sort of live arraylike collection.  The problem here is that in most cases the liveness means that the DOM implementation needs to be able to write into the array but callers need to not be able to do so.  What that means is that the script-visible behavior is basically some sort of proxy around an Array.

After a brief chat with darobin in IRC, I am no longer convinced this is a bad pattern, if done correctly. The difference between an array that does this (via proxies) and an object that does this (via getters) seems insubstantial.

But, the correct way to do this needs some noodling before we even consider recommending it; the current patterns in the platform are scary. I'll try to make some time to draw up a readonly-array direct proxy that feels intuitive enough that we could consider using it. It might not be possible.
Comment 11 Boris Zbarsky 2013-07-10 21:10:49 UTC
> I am no longer convinced this is a bad pattern, if done correctly.

For what it's worth, the usual arguments I've heard against live lists fall into two categories:

1)  They're hard to iterate over: you have to make sure that nothing modifies the list as a side-effect while you're iterating.  Here's a common pitfall people fall into, for example:

  var kids = myNode.childNodes;
  for (var i = 0; i < kids.length; ++kids) {
    myNode.removeChild(kids[i]);
  }

2)  They impose a performance burden on implementations that have to update the list whenever the set of things it reflects changes.  This is maybe counterbalanced by the fact that live lists can sometimes do less work than non-live ones (e.g. getElementsByTagName("foo")[0] doesn't have to walk the whole DOM, just until it finds the first <foo>).
Comment 12 Domenic Denicola 2016-09-08 20:56:33 UTC
Since array[]s were removed, I guess we've provided all the necessary guidance ^_^