Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editorial: describe behavior for algorithms without a "Return" #2397

Closed
wants to merge 3 commits into from

Conversation

bakkot
Copy link
Contributor

@bakkot bakkot commented Apr 29, 2021

Fixes #2394.

@@ -3574,7 +3569,7 @@ <h1>Await</h1>
1. Perform ! PerformPromiseThen(_promise_, _onFulfilled_, _onRejected_).
1. Remove _asyncContext_ from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
1. Set the code evaluation state of _asyncContext_ such that when evaluation is resumed with a Completion _completion_, the following steps of the algorithm that invoked Await will be performed, with _completion_ available.
1. Return.
1. Return NormalCompletion(~unused~).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this one need an explicit return statement at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not strictly necessary, but I think it's helpful so that the "this" in the immediately following note is clear.

Copy link
Collaborator

@jmdyck jmdyck Apr 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the subsequent NOTE-step needs something to refer to?
[was replying to ljharb, github didn't show me bakkot's response for some reason.]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure the note could be reworded to refer to the implicit return behavior without the need for a placeholder step, if that were desired.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the subsequent NOTE-step needs something to refer to?

Yes. It could probably be rephrased, but I like this wording.

Comment on lines +39480 to 39482
1. [id="step-asyncfunctionstart-return-undefined"] Return NormalCompletion(~unused~).
1. Push _asyncContext_ onto the execution context stack; _asyncContext_ is now the running execution context.
1. Resume the suspended evaluation of _asyncContext_. Let _result_ be the value returned by the resumed computation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this correct, given that 2 lines down, the returned value is used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not regard the assertion as using the value.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

additionally, the step ID says "return undefined" - is it not important that it's "undefined" versus an unused value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that's just an arbitrary label for making the later step reference work. I didn't change it because step IDs don't yet support oldids and I didn't want to break existing links.

@bakkot
Copy link
Contributor Author

bakkot commented Apr 29, 2021

I note that this races with two new usages of Return. in #1668, and whichever lands second will need to be rebased. I'm happy to do that myself, I'm just commenting so we don't lose track.

@michaelficarra
Copy link
Member

Thinking about this more, we could instead use a new kind of completion record here (just for procedure early exits) that doesn't have a [[Value]] slot, making the attempt to use the value of an AO that returns it an editorial type error through existing means.

@bakkot
Copy link
Contributor Author

bakkot commented Apr 29, 2021

I would prefer not to further complicate the distinction between normal and abrupt completions, I think.

@michaelficarra
Copy link
Member

Yeah, I think I agree. We might be able to make some improvements in this area once completion value reform is complete.

<emu-alg>
1. Return NormalCompletion(*undefined*).
</emu-alg>
<p>If all steps in an abstract operation have been executed without returning, the abstract operation behaves as though there were an additional step reading "Return NormalCompletion(~unused~)." after the existing steps. ~unused~ is a special value which is never directly consumed.</p>
Copy link
Collaborator

@jmdyck jmdyck Apr 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"If all steps in an abstract operation have been executed without returning..."

Well, not necessarily all steps, because if there are If-else-steps, we might have executed only one of the arms. Maybe "If an abstract operation completes execution without returning ..." ?

Also, it's not just abstract operations, there's at least one syntax-directed operation (ForDeclarationBindingInstantiation) that this applies to. (Or maybe you consider SDOs a subset of AOs, which the spec isn't entirely clear on.)


"~unused~ is a special value which is never directly consumed."

So it might be indirectly consumed? What does that even mean?

Maybe "~unused~ is an ad hoc value that is only used for this purpose."


Also maybe "Operations that return ~unused~ are typically invoked in a Perform step." (I only found one exception, where AsyncGeneratorEnqueue has Let _check_ be AsyncGeneratorValidate(...).)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say "Operations that return ~unused~ must only be invoked in a Perform step.`

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So then what about the AsyncGeneratorEnqueue case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmdyck

Well, not necessarily all steps, because if there are If-else-steps, we might have executed only one of the arms.

I was modeling the if-else as a single step (with the arms being substeps), but I can see how your interpretation is plausible.

Maybe "... completes execution without returning ..." ?

I'd be OK with that, though I don't love it. Open to other phrasings here.

I originally said something like "if control reaches the end of the algorithm", but I felt that was maybe too confusing, since we normally talk about control-flow of the JS being executed rather than of spec steps.

Also, it's not just abstract operations, there's at least one syntax-directed operation (ForDeclarationBindingInstantiation) that this applies to. (Or maybe you consider SDOs a subset of AOs, which the spec isn't entirely clear on.)

For avoidance of doubt I'll list SDOs explicitly.

So it might be indirectly consumed? What does that even mean?

It means the completion containing it is consumed, or it's stored in a binding within a macro but the binding is not used after the macro, etc. I am content with this phrasing personally; does anyone else want to weigh in?

@ljharb

Operations that return ~unused~ must only be invoked in a Perform step

That's not a guarantee I want to make: it is reasonable to have instances of the pattern

1. Let _result_ be SomeProcedure(whatever).
1. If _result_ is an abrupt completion, then
  1. Do some cleanup. 

Copy link
Member

@ljharb ljharb Apr 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's a good question/point about those cases. I don't have a suggestion.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was modeling the if-else as a single step (with the arms being substeps),

Indeed, that's how structured programming wants us to think of it, but when each Else has a different step-number, it's harder to suggest that they're not different steps.

Maybe "... completes execution without returning ..." ?

I'd be OK with that, though I don't love it.

Yeah, I'm not thrilled with it either. The problem is, the existing spec gives us almost no terminology/model for the execution of algorithms.

I originally said something like "if control reaches the end of the algorithm", but I felt that was maybe too confusing, since we normally talk about control-flow of the JS being executed rather than of spec steps.

Yeah, I don't see any examples of the spec using "control" in the context of performing spec steps. At least for "execute" there are a handful of examples.

@bakkot
Copy link
Contributor Author

bakkot commented Jun 11, 2021

This should wait on #2413 / #2429, which touch several of the same places.

@ljharb ljharb force-pushed the master branch 3 times, most recently from 3d0c24c to 7a79833 Compare June 29, 2021 02:21
@jmdyck
Copy link
Collaborator

jmdyck commented Feb 10, 2022

I think, once PR #2547 lands, you won't need this PR any more, because there won't be any algorithms that complete without a Return.

Or I suppose you could say that if it happens it's an editorial error.

@jmdyck
Copy link
Collaborator

jmdyck commented Mar 10, 2022

If you rebase to main (now that #2547 has landed), I think you'll find that there isn't much left in this PR.

Note that 9.10.3 Execution doesn't have a "Return" step, so you might want to add a Return ~unused~. On the other hand, it's a weird case, so maybe "Return" doesn't mean anything?

@bakkot
Copy link
Contributor Author

bakkot commented Feb 15, 2023

Fixed by #2547 instead.

@bakkot bakkot closed this Feb 15, 2023
@bakkot bakkot deleted the return branch February 15, 2023 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"Return" at end of algorithm: implicit or explicit?
6 participants