The spec in Implicit Normal Completion says,
In algorithms within abstract operations which are declared to return a Completion Record, within the Evaluation syntax-directed operation, and within all built-in functions, the returned value is first passed to NormalCompletion, and the result is used instead.
Why the algorithms implicitly return some kind Completion Record when the implementations(browsers or nodejs) don't implement it?
I'm I missing some part of the spec that says like that the implementations must return the
Completion Records are how the spec models exception handling (as well as other kinds of abrupt exits like
break). These are unwrapped before passing to code (with the ubiquitous
? macro, generally), so code will never see an actual Completion Record, but they're necessary internally to model control flow.
Thanks for your answer. But I'm still not clear. Could you please tell me, where do the spec makes it clear that implementations must use the unwraped return value. I understand that the ? shorthand is used to unwrap values inside algorithm steps like macros in C. But Implicit Normal Completion always ensures the return value is a Completion Record. My confusion starts from there. For example in Array.prototype.includes:
I've noticed in a prior spec version there is a clear explanation as below:
Any reference to a Completion Record value that is in a context that does not explicitly require a complete Completion Record value is equivalent to an explicit reference to the [[value]] field of the Completion Record value unless the Completion Record is an abrupt completion.
But in latest spec I don't see any such clarification. Is it said in a different way somewhere else in the spec? Or they decided to leave the decision to the implementers?
I think the important thing to understand is that, when you call a built-in function, the algorithm that appears in the spec doesn't directly supply the value that your code receives.
For example, for the assignment
x = isNaN(1), here's what happens (I think):
- In the algorithm for isNaN, step 3 specifies
- That value is passed to NormalCompletion, according to the Implicit Normal Completion rules.
- The resulting Completion Record is bound to
_result_ in step 10 of the [[Call]] internal method for built-in functions.
- A couple steps later,
[[Call]] returns that value...
- ... to the Call abstract operation, which immediately returns it ...
- ... to the EvaluateCall abstract operation, which immediately returns it ...
- ... to the Evaluation semantics for CallExpression, which immediately returns it ...
- ... to step 1.d.i in the Evaluation semantics for AssignmentExpression, where it's bound to
- On the next step, that's passed to GetValue (as the
- In step 1 of GetValue,
_V_ is passed to ReturnIfAbrupt, which is sort-of a macro that 'unwraps' the Completion Record, and binds its
*false*) back to
- On step 2, since
_V_ is a Boolean, not a Reference Record, it's returned ...
- ... back to the Evaluation semantics, where it gets bound to
- And on the next step (1.e),
_rval_ is passed to the
PutValue operation, which has the effect of setting your
x variable to
So, roughly speaking, it's the call to ReturnIfAbrupt in GetValue that tells implementations to return the
[[Value]] field of the Completion Record returned by the spec algorithm of a built-in function.
Thank you very much for the detailed explanation. I was trying to understand it the whole yesterday. After reading your answer, finally I understand what's happening! Hurray!!!