w3c / FileAPI

File API
https://w3c.github.io/FileAPI/
Other
104 stars 44 forks source link

Make the FileList interface iterable #94

Closed DavidBruant closed 6 years ago

DavidBruant commented 6 years ago

https://heycam.github.io/webidl/#idl-iterable over the files, i guess

inexorabletash commented 6 years ago

See https://heycam.github.io/webidl/#es-iterators

Since FileList has an indexed property getter and an integer-typed length attribute it is implicitly iterable. No need for an explicit declaration in the spec.

(I forget this on a regular basis and almost suggested the same thing a few weeks ago.)

In Chrome !!FileList.prototype[Symbol.iterator] is true. If other browsers don't support that it's a bug in their bindings implementation.

inexorabletash commented 6 years ago

It doesn't look like idlharness has a case for this yet. Filed https://github.com/w3c/web-platform-tests/issues/8616

jaydenseric commented 3 years ago

I've been up all night trying to figure out the answer to 2 questions:

  1. By spec, can a FileList instance be iterated using for…of and spread with ... syntax?
  2. What browsers support doing that?

I can't find a confident answer to either question.

The Google Closure compiler team thinks the spec says FileList is not iterable:

https://github.com/google/closure-compiler/issues/3231#issuecomment-463011621

Are they wrong?

The spec for the FileList interface doesn't say it's iterable in the IDL:

[Exposed=(Window,Worker), Serializable]
interface FileList {
  getter File? item(unsigned long index);
  readonly attribute unsigned long length;
};

https://www.w3.org/TR/FileAPI/#filelist-section

Yet, for contrast the the spec for NodeList explicitly says it's iterable:

[Exposed=Window]
interface NodeList {
  getter Node? item(unsigned long index);
  readonly attribute unsigned long length;
  iterable<Node>;
};

https://dom.spec.whatwg.org/#interface-nodelist

Why the difference? Both are often referred to as "array-like".

Side note: I've gone around in circles trying to figure out the meaning of the term "array-like", and have come to the conclusion it's a useless term because it's been in use since before iterators were a thing, and it's hard to tell if it's being used to describe an object with only integer index and length properties, or also with [Symbol.iterator]() { so it can be spreadable with ... and iterated with for…of. It took me a while to figure out for…of is only intended to work with iterables, and not legacy "array-like" objects.

I tried this in Node.js and Safari and it bombs:

for (const item of {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3,
})
  console.log(item);

@inexorabletash

Since FileList has an indexed property getter and an integer-typed length attribute it is implicitly iterable. No need for an explicit declaration in the spec.

You seem to say only integer index and length properties are required to make an object iterable (which I interpret to mean spreadable and loopable via for…of). As I mentioned above, I don't think this is true. But then you go on to say:

In Chrome !!FileList.prototype[Symbol.iterator] is true. If other browsers don't support that it's a bug in their bindings implementation.

What justification do you have to say it would be a bug? Where does the spec say FileList is iterable?

If the most popular browsers (i.e. Chrome) are making FileList iterable via [Symbol.iterator]() {, then should the spec be changed to align with implementations and developer expectations?

There is no caniuse.com entry for FileList @@iterator support:

https://caniuse.com/?search=FileList

So, I've messaged friends and family to try testing this codepen out with browsers matched by this browserslist query:

https://codepen.io/jaydenseric/pen/BaWOWQj?editors=1011

> 0.5%, not OperaMini all, not IE > 0, not dead

My motivation for all these questions is that as part of the next major extract-files (> 1.7 million installs per week) release, I intend to iterate both normal arrays and FileList instances via the same for…of loop.

saschanaz commented 3 years ago

The Web IDL spec implicitly makes FileList iterable, since it has an indexed property getter (the getter File? item(unsigned long index); part). FileList.prototype[Symbol.iterator] is thus defined on all browsers and that makes for-of/... work.

iterable<> in NodeList just adds more functions like forEach().

jaydenseric commented 3 years ago

Thanks for the clarifications. I've tried my best tonight to try to understand what an "indexed property getter" is, but still can't find a plain english explanation anywhere.

Does that mean that the object has properties that are numbers? E.g.

const x = { 0: 'a', 1: 'b', 2: 'c' };

Is it the same if you did:

const x = { '0': 'a', '1': 'b', '2': 'c' };

It would be a big help for people learning about this if the MDN article for FileList showed examples of iteration using spread and for…of:

https://developer.mozilla.org/en-US/docs/Web/API/FileList

There is no mention anywhere of FileList being iterable and it only shows an old-school for loop.

saschanaz commented 3 years ago

An indexed property getter is an operation marked as getter, as seen in FileList IDL definition.

Adding some example to MDN sounds good, you can file an issue from the bottom of the page.

jaydenseric commented 3 years ago

Ok, thank you; I think I get it now.

I thought "indexed property getter" meant something about the object itself, as if you could make a custom object that has an "indexed property getter". But actually, it means a spec basically notes that that a particular getter method on a particular standard web platform object is the way to access the index properties, and therefore that object is implicitly iterable. In the case of FileList, the FileList instance method item is specially identified in the spec as the indexed property getter that makes FileList implicitly iterable.

annevk commented 3 years ago

FWIW, it does seem reasonable to add iterable<File> to FileList, but that should probably happen through a new issue.