Closed
Bug 938704
Opened 12 years ago
Closed 8 years ago
Make OS.File support ES6 iterators
Categories
(Toolkit Graveyard :: OS.File, defect)
Toolkit Graveyard
OS.File
Tracking
(firefox57 fixed)
RESOLVED
FIXED
mozilla57
| Tracking | Status | |
|---|---|---|
| firefox57 | --- | fixed |
People
(Reporter: bbenvie, Assigned: emk)
References
(Blocks 1 open bug)
Details
(Whiteboard: [Async:team])
Attachments
(1 file, 6 obsolete files)
Right now OS.File supports the legacy __iterator__ that overloads for-in and also uses StopIteration. OS.File should be upgraded to use ES6 style iterators which use @@iterator and return `{ done, value }` on each iteration, rather than using StopIteration.
Comment 1•12 years ago
|
||
For reference, here's a guide to @@iterator: http://domenic.me/2013/09/06/es6-iterators-generators-and-iterables/
Comment 2•12 years ago
|
||
Looks like we're going to make some unhappy clients. The __iterator__ + StopIteration played nicely with throwing StopIteration from a generator, this new version doesn't seem so accommodating.
Keywords: addon-compat
Comment 3•12 years ago
|
||
Ok, it's officially worse: __iterator__ supports |for in|, @@iterator supports |for of|.
I'll probably need to add a transitional __iterator__ wrapper.
Comment 4•12 years ago
|
||
Here we go.
Assignee: nobody → dteller
Attachment #8337968 -
Flags: review?(nfroyd)
Attachment #8337968 -
Flags: review?(bbenvie)
Comment 5•12 years ago
|
||
And the tests.
I took the opportunity to remove the async DirectoryIterator tests from mochi/ and into xpcshell/.
Attachment #8337970 -
Flags: review?(nfroyd)
Updated•12 years ago
|
Whiteboard: [Async]
| Reporter | ||
Comment 6•12 years ago
|
||
Comment on attachment 8337968 [details] [diff] [review]
Porting OS.File to @@iterator
Review of attachment 8337968 [details] [diff] [review]:
-----------------------------------------------------------------
Mostly looks good! A few fixes and nits.
::: toolkit/components/osfile/modules/osfile_async_front.jsm
@@ +921,2 @@
> */
> + next: function() {
Nit: `next: function next() {` maybe? To follow the style of rest of the methods.
@@ +928,5 @@
> + if (done) {
> + this.close();
> + return this._itmsg;
> + }
> + return value;
This should be `return DirectoryIterator.Entry.fromMsg(value)`.
@@ +929,5 @@
> + this.close();
> + return this._itmsg;
> + }
> + return value;
> + }.this);
`.bind(this)`, or use an arrow function.
@@ +981,2 @@
> let position = 0;
> + return Task.spawn(function() {
Should probably use function* here.
@@ +987,5 @@
> + yield Scheduler.post("DirectoryIterator_prototype_next", [iterator]);
> + if (done) {
> + break;
> + }
> + yield cb(value, position++, this);
Also need `DirectoryIterator.Entry.fromMsg(value)` here.
Attachment #8337968 -
Flags: review?(bbenvie) → review+
Comment 7•12 years ago
|
||
Comment 8•12 years ago
|
||
(In reply to Brandon Benvie [:benvie] from comment #6)
> This should be `return DirectoryIterator.Entry.fromMsg(value)`.
Ah, right. Since that's basically identity, I would have missed that.
> @@ +929,5 @@
> > + this.close();
> > + return this._itmsg;
> > + }
> > + return value;
> > + }.this);
>
> `.bind(this)`, or use an arrow function.
Wow. I'm shocked that this didn't throw a SyntaxError.
> @@ +981,2 @@
> > let position = 0;
> > + return Task.spawn(function() {
>
> Should probably use function* here.
I thought that function* was disabled for the moment?
Comment 9•12 years ago
|
||
Applied benvie's feedback.
Attachment #8337968 -
Attachment is obsolete: true
Attachment #8337968 -
Flags: review?(nfroyd)
Attachment #8338036 -
Flags: review?(nfroyd)
| Reporter | ||
Comment 10•12 years ago
|
||
(In reply to David Rajchenbach Teller [:Yoric] <needinfo? me> from comment #8)
> I thought that function* was disabled for the moment?
I believe it was disabled for aurora but that was a temporary thing (not sure if they're still disabled on Aurora or not). It's being used in a number of places in m-c now (http://mxr.mozilla.org/mozilla-central/search?string=function*&find=\.jsm*&findi=&filter=^[^\0]*%24&hitlimit=&tree=mozilla-central).
Comment 11•12 years ago
|
||
Comment on attachment 8338036 [details] [diff] [review]
Porting OS.File to @@iterator, v2
Review of attachment 8338036 [details] [diff] [review]:
-----------------------------------------------------------------
r=me with fixing the Unix/Windows inconsistency.
::: toolkit/components/osfile/modules/osfile_async_front.jsm
@@ +929,5 @@
> + this.close();
> + return this._itmsg;
> + }
> + return DirectoryIterator.Entry.fromMsg(value);
> + }.bind(this));
Do we have fat arrow functions available nowadays? We could probably dispense with .bind()s here and elsewhere. Followup bug, perhaps?
::: toolkit/components/osfile/modules/osfile_unix_front.jsm
@@ +698,5 @@
> if (!this._exists) {
> throw File.Error.noSuchFile("DirectoryIterator.prototype.next");
> }
> if (this._closed) {
> + return {done: true, value: undefined};
We have disagreements between the Unix and Windows versions about what |value| is when we're done (undefined here, null for windows). For consistency's sake, we should make them the same.
Alternatively, we could have AbstractIterator define a DONE_OBJECT or somesuch that we could always use in these situations.
Attachment #8338036 -
Flags: review?(nfroyd) → review+
Comment 12•12 years ago
|
||
Comment on attachment 8337970 [details] [diff] [review]
Companion tests
Review of attachment 8337970 [details] [diff] [review]:
-----------------------------------------------------------------
r=me, but why did you pull the test out to its own file and change the iteration details in a single patch?
Attachment #8337970 -
Flags: review?(nfroyd) → review+
(In reply to Nathan Froyd (:froydnj) from comment #11)
> Comment on attachment 8338036 [details] [diff] [review]
> Porting OS.File to @@iterator, v2
>
> Review of attachment 8338036 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> r=me with fixing the Unix/Windows inconsistency.
>
> ::: toolkit/components/osfile/modules/osfile_async_front.jsm
> @@ +929,5 @@
> > + this.close();
> > + return this._itmsg;
> > + }
> > + return DirectoryIterator.Entry.fromMsg(value);
> > + }.bind(this));
>
> Do we have fat arrow functions available nowadays? We could probably
> dispense with .bind()s here and elsewhere. Followup bug, perhaps?
I don't really like fat arrow functions for multiline functions. If you wish, I can file a followup bug nevertheless, though.
>
> ::: toolkit/components/osfile/modules/osfile_unix_front.jsm
> @@ +698,5 @@
> > if (!this._exists) {
> > throw File.Error.noSuchFile("DirectoryIterator.prototype.next");
> > }
> > if (this._closed) {
> > + return {done: true, value: undefined};
>
> We have disagreements between the Unix and Windows versions about what
> |value| is when we're done (undefined here, null for windows). For
> consistency's sake, we should make them the same.
>
> Alternatively, we could have AbstractIterator define a DONE_OBJECT or
> somesuch that we could always use in these situations.
Actually, the value is ignored, so it's not a big deal, but let's make it |undefined|.
Applied feedback.
Try: https://tbpl.mozilla.org/?tree=Try&rev=b8602e81e8f3
Attachment #8338036 -
Attachment is obsolete: true
Attachment #8346620 -
Flags: review+
Updated•12 years ago
|
Whiteboard: [Async] → [Async:team]
Comment 15•10 years ago
|
||
Can somebody commit to working on this? As far as I can tell this is the biggest hurdle to removing __iterator__, which causes ES6 problems.
Review commit: https://reviewboard.mozilla.org/r/23917/diff/#index_header
See other reviews: https://reviewboard.mozilla.org/r/23917/
Updated•10 years ago
|
Attachment #8337970 -
Attachment is obsolete: true
Updated•10 years ago
|
Attachment #8338017 -
Attachment is obsolete: true
Updated•10 years ago
|
Attachment #8346620 -
Attachment is obsolete: true
Looks like I won't have time to work on this, so I have pushed a WIP. If my memory serves, all of OS.File is ported to ES6 iterators, but not all client code. If anybody wants to take this forward, please be my guest.
Assignee: dteller → nobody
Comment 18•8 years ago
|
||
bug 1331092 (and async iteration protocol) may be interesting for this case, given that this is asynchronous iteration.
Comment 19•8 years ago
|
||
David, is there anybody on the Firefox team who could work on this?
Flags: needinfo?(dteller)
I suspect that Paolo would know better than me.
Flags: needinfo?(dteller) → needinfo?(paolo.mozmail)
Comment 21•8 years ago
|
||
At present most of us are busy with Firefox 57, but it's something we could work on afterwards, if this is the question :-)
In some cases, we may have an opportunity for using async generators as well. We should also wait a few releases to do that as they're a pretty new feature in our JavaScript engine.
Flags: needinfo?(paolo.mozmail)
| Comment hidden (mozreview-request) |
| Assignee | ||
Comment 23•8 years ago
|
||
We don't have to care about addon-compat anymore.
| Assignee | ||
Updated•8 years ago
|
Attachment #8703655 -
Attachment is obsolete: true
Comment 24•8 years ago
|
||
| mozreview-review | ||
Comment on attachment 8899232 [details]
Bug 938704 - Make OS.File support modern iterators.
https://reviewboard.mozilla.org/r/170494/#review175824
That looks like a nice simplification, thanks!
::: toolkit/components/osfile/modules/osfile_async_front.jsm
(Diff revision 1)
> - return Promise.resolve();
> + return undefined;
> }
> this._isClosed = true;
> - let self = this;
> - return this._itmsg.then(
> + let iterator = this._itmsg;
> + this._itmsg = null;
> - function withIterator(iterator) {
I believe that the comment was useful. Could you keep/adapt it?
::: toolkit/components/osfile/modules/osfile_async_worker.js:366
(Diff revision 1)
> - try {
> - return File.DirectoryIterator.Entry.toMsg(this.next());
> + let {value, done} = this.next();
> + if (done) {
> - } catch (x) {
> - if (x == StopIteration) {
> - OpenedDirectoryIterators.remove(dir);
> + OpenedDirectoryIterators.remove(dir);
> + return { done: true };
For (shape) consistency, shouldn't you return
```js
{ value: undefined, done: true }
```
and
```js
{ value: File.DirectoryIterator.Entry.toMsg(value), done: false }
```
?
Also, the same wherever you return `{ value: ... }` or `{done: ...}`.
::: toolkit/components/search/nsSearchService.js:2981
(Diff revision 1)
> distDirs.push(dir);
> } catch (ex) {
> - // Catch for StopIteration exception.
> if (ex.result == Cr.NS_ERROR_ALREADY_INITIALIZED) {
> throw ex;
> }
Mmmh... that looks weird. I realize it already looked weird before your patch, but someone should probably audit these lines.
::: toolkit/components/search/nsSearchService.js
(Diff revision 1)
> try {
> // Add dir to otherDirs if it contains any files.
> await checkForSyncCompletion(iterator.next());
> otherDirs.push(dir);
> } catch (ex) {
> - // Catch for StopIteration exception.
Same here.
Attachment #8899232 -
Flags: review?(dteller) → review+
| Assignee | ||
Comment 25•8 years ago
|
||
| mozreview-review-reply | ||
Comment on attachment 8899232 [details]
Bug 938704 - Make OS.File support modern iterators.
https://reviewboard.mozilla.org/r/170494/#review175824
> I believe that the comment was useful. Could you keep/adapt it?
Since we no longer lazyly initialize a rejected promise and now we always chack isClosed before touching _itmsg, I'm not sure we have anything to note here.
> For (shape) consistency, shouldn't you return
>
> ```js
> { value: undefined, done: true }
> ```
>
> and
>
> ```js
> { value: File.DirectoryIterator.Entry.toMsg(value), done: false }
> ```
>
> ?
>
> Also, the same wherever you return `{ value: ... }` or `{done: ...}`.
Done.
> Mmmh... that looks weird. I realize it already looked weird before your patch, but someone should probably audit these lines.
Indeed the previous version did not keep the semantics, thanks.
| Comment hidden (mozreview-request) |
| Assignee | ||
Comment 27•8 years ago
|
||
| mozreview-review | ||
Comment on attachment 8899232 [details]
Bug 938704 - Make OS.File support modern iterators.
https://reviewboard.mozilla.org/r/170494/#review175912
::: commit-message-5ca56:1
(Diff revision 2)
> +Bug 938704 - Make OS.File support modern iterators. r?Yoric,florian
Florian, could you double-check the nsSearchService.js change?
Comment 28•8 years ago
|
||
| mozreview-review | ||
Comment on attachment 8899232 [details]
Bug 938704 - Make OS.File support modern iterators.
https://reviewboard.mozilla.org/r/170494/#review175962
::: .eslintignore:359
(Diff revision 2)
> toolkit/modules/AppConstants.jsm
> toolkit/mozapps/downloads/nsHelperAppDlg.js
> toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
>
> +# Uses for-await-of syntax
> +toolkit/mozapps/extensions/internal/XPIProvider.jsm
Not linting the whole file for a problem on a single line doesn't seem great. Can we use // eslint-disable-line instead?
::: toolkit/components/search/nsSearchService.js:2980
(Diff revision 2)
> // Add dir to distDirs if it contains any files.
> - await checkForSyncCompletion(iterator.next());
> + let {done} = await checkForSyncCompletion(iterator.next());
> + if (!done) {
> - distDirs.push(dir);
> + distDirs.push(dir);
> + }
> } catch (ex) {
Do we still need this catch block?
::: toolkit/components/search/nsSearchService.js:3006
(Diff revision 2)
> // Add dir to otherDirs if it contains any files.
> - await checkForSyncCompletion(iterator.next());
> + let {done} = await checkForSyncCompletion(iterator.next());
> + if (!done) {
> - otherDirs.push(dir);
> + otherDirs.push(dir);
> + }
> } catch (ex) {
Same question here.
::: toolkit/mozapps/extensions/internal/XPIProvider.jsm:6570
(Diff revision 2)
> logger.error("Failed to clean updated system add-ons directories.", e);
> return;
> }
>
> try {
> - for (let promise in iterator) {
> + for await (let entry of iterator) {
Are we sure it's OK to use 'for await'? https://groups.google.com/forum/#!topic/mozilla.dev.platform/J1cSMVqwZAY seems to say we should wait a cycle or two.
Attachment #8899232 -
Flags: review?(florian)
| Assignee | ||
Comment 29•8 years ago
|
||
| mozreview-review-reply | ||
Comment on attachment 8899232 [details]
Bug 938704 - Make OS.File support modern iterators.
https://reviewboard.mozilla.org/r/170494/#review175962
> Not linting the whole file for a problem on a single line doesn't seem great. Can we use // eslint-disable-line instead?
ESLint does not support the for-await-of syntax at all yet. It does not even parse this file as a valid JavaScript file. So I had no choice.
That said, it does not matter anymore because I retracted the use of for-await-of. (See below.)
> Do we still need this catch block?
Yes. checkForSyncCompletion may throw NS_ERROR_ALREADY_INITIALIZED. (The old comment was a bit misleading.)
> Are we sure it's OK to use 'for await'? https://groups.google.com/forum/#!topic/mozilla.dev.platform/J1cSMVqwZAY seems to say we should wait a cycle or two.
Hmm, I had to re-introduce `__iterator__` and manually implement the async iterator protocol at the moment :(
| Comment hidden (mozreview-request) |
| Comment hidden (mozreview-request) |
Comment 32•8 years ago
|
||
(In reply to Masatoshi Kimura [:emk] from comment #29)
> > Do we still need this catch block?
>
> Yes. checkForSyncCompletion may throw NS_ERROR_ALREADY_INITIALIZED. (The old
> comment was a bit misleading.)
We specifically don't want to catch NS_ERROR_ALREADY_INITIALIZED, that's why we throw it again if it's the exception that got caught. I don't think the old comment was misleading.
| Assignee | ||
Comment 33•8 years ago
|
||
Hm, the old code used to swallow all exceptions but NS_ERROR_ALREADY_INITIALIZED. It should have been?
if (ex != StopIteration) {
?
| Comment hidden (mozreview-request) |
Comment 35•8 years ago
|
||
as long as DirectoryIterator.prototype implements async iteration protocol, you can iterate over it manually with something like the following, without adding __iterator__.
let asyncIterator = Symbol.asyncIterator || "@@asyncIterator";
let DirectoryIterator.prototype = {
[asyncIterator]() {
return this;
},
...
};
let iter = iterator[asyncIterator]();
try {
for (;;) {
let {value: entry, done} = await iter.next();
if (done) {
iter = null;
break;
}
/* loop body here */
}
} finally {
if (iter && "return" in iter && typeof iter.return == "function") {
iter.return();
}
}
Comment 36•8 years ago
|
||
also, in that case iterator.close call can be stored into iterator.return, that will be called automatically if you switch to for-await-of.
> let DirectoryIterator.prototype = {
s/let //
| Comment hidden (mozreview-request) |
| Assignee | ||
Comment 38•8 years ago
|
||
Instead of strictly adhering the async iterator protocol, I used the knowledge of implemention details of DirectoryIterator. For example, I omitted iterator[Symbol.asyncIterator]() because it will just return itself.
Comment 39•8 years ago
|
||
| mozreview-review | ||
Comment on attachment 8899232 [details]
Bug 938704 - Make OS.File support modern iterators.
https://reviewboard.mozilla.org/r/170494/#review176350
Looks good to me, thanks!
Attachment #8899232 -
Flags: review?(florian) → review+
Comment 40•8 years ago
|
||
Pushed by VYV03354@nifty.ne.jp:
https://hg.mozilla.org/integration/autoland/rev/7f2356284595
Make OS.File support modern iterators. r=florian,Yoric
Comment 41•8 years ago
|
||
| bugherder | ||
Status: ASSIGNED → RESOLVED
Closed: 8 years ago
status-firefox57:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla57
Updated•2 years ago
|
Product: Toolkit → Toolkit Graveyard
You need to log in
before you can comment on or make changes to this bug.
Description
•