In streams, which is heavily promise-based, there are a lot of abstract operations that cannot throw. The ES spec has these too, in smaller number.
Of course, this kind of nothrow vs. throw characteristic can be contagious. If you only use nothrow abstract ops in your abstract op, then your abstract op is nothrow. Whereas if you use any throwing ops, you are now throwing. Unless you are certain for external reasons that the given throw operation will not throw in this context, in which case you might want to assert that it is a non-abrupt-completion.
There are a couple action items here, some of which can be done independently:
Let _result_ be ! AbstractOp(). Use it throughout. A lot of places in the spec currently use "perform" for this purpose, which is not defined anywhere.<emu-clause nothrow> or <emu-clause flair="nothrow">.What about the case where the result of AbstractOp is not needed? That's usually the cases where "Perform" appears. Having a useless _result_ doesn't seem ideal. Do you have an alternative suggestion for an abstract op that solely causes side effects (some of which can throw, and some of which can't)?
In general I love this idea - being explicit about what can throw and what can't seems like an overall improvement.
Do you have an alternative suggestion for an abstract op that solely causes side effects (some of which can throw, and some of which can't)?
1. ? AbstractOp() to bubble errors, or 1. ! AbstractOp() to assert it never errors. You could introduce the "perform" verb for that but I'd like it to be defined this time.
Sounds good - I like having an explicit "this is for side effects" mechanism like "Perform".
Here's what I said when this was raised in the ecmarkup repo:
Presumably "Perform AbstractOp(x)" implies not just that AbstractOp doesn't throw, but also that it doesn't return anything useful (via normal completion). (Or at least, that these things are known to be true for the particular arguments being passed.)
I think it would be ideal if Ecmarkup supported this, e.g.
<h1 aoid="..." nothrow>...</h1>.
To generalize your suggestion, I think it would be useful (though even more work) if every operation had a "header" that systematically listed/described the operation's inputs (parameters) and outputs (returns). (Currently, preambles give some of this info, but not consistently or completely.) E.g., outputs/returns might say something like:
normal returns: Boolean
abrupt returns: TypeError
So the throw/nothrow distinction would be captured by whether any abrupt returns are listed.
@jmdyck: that would be amazing, but much work... I think we can probably get there eventually by going down the path of incrementally adding !.
Note that Perform X() is not about implying that AbstractOp doesn't throw (note further the many instances of Perform ? Op()). It's simply ecmaspeak for "the result of X()" where x doesn't have a useful result. In other words, with bang, if an abstract op doesn't have a useful result, we'd want Perform ! Op().
I fully support ! as a short-hand for "Assert: previous thing is not an abrupt completion". We can probably just start the incremental addition by doing a similar regexp replace as we did to kick off the ? conversion.
I'm a little worried about extending the ECMASpeak programming language too fast. The RIA shorthand was a good buy in terms of readability/writability, but I'm not so sure about "!".
@jmdyck: that would be amazing, but much work...
I'm prepared to do the work if we can agree on a "header" syntax.
I'm a fan of !. It fixes two important problems with the current spec:
I am less of a fan of the header syntax, but some mock-up screenshots could possibly convince me.
ToString returns a completion value, but CreateDataProperty does not accept completion values as its second argument. This is just a bug in the current spec really. (Or if you prefer, an intentional type mismatch for the sake of brevity.)
No, it is a specified and documented feature of completion records to allow implicit access to the [[value]] field (cf. 6.2.2.2).
How about doing it the other way around: Explicitly state with ! when a caller needs to receive a completion record. I think that should be more ergonomic than adding ! after every infallible operation.
@anba, please no. The spec should not be optimised for maximum brevity but for maximum clarity. I think the implicit conversion from completion records to their values is actively harmful in that regard. There are already too many hidden conventions going on in the spec (a criticism I keep hearing from fellow V8 implementers trying to make sense of it every other day).
No, it is a specified and documented feature of completion records to allow implicit access to the [[value]] field (cf. 6.2.2.2).
Yes, that is what I meant in the parenthetical.
I think the implicit conversion from completion records to their values is actively harmful in that regard.
I agree. (And also the reverse implicit conversion.)
I've thought of an approach that I think would eliminate most of these conversions. I'll raise it in another issue when I have some time.
I want to support the general position expressed by @rossberg-chromium above.
Maximizing clarity (and particularly for occasional readers should be among the highest priorities. Most readers of the spec. are not spending 8 hours a day emerged within it. More likely they are occasionally looking up some specific details. They may or may not have read the clause 5 conversions and even if they have they may not remember them what they read.
@domenic things like CreateDataProperty(_array_, ToString(_n_), _e_) is used in situations where _n_ is known to have a value that will convert to a string, without error. Most typically this is an integer valued index variable of a algorithmic loop. I considered making the conversion from completion to value explicit but found that formulation to be less readable.
Going to close this issue as I believe we have satisfied the original request.
I don't believe we have. The first bullet point is mostly implemented, but the overall request motivating it (as outlined in the subsequent ones) remains open.
Oh I see, sorry about that.
Most helpful comment
@anba, please no. The spec should not be optimised for maximum brevity but for maximum clarity. I think the implicit conversion from completion records to their values is actively harmful in that regard. There are already too many hidden conventions going on in the spec (a criticism I keep hearing from fellow V8 implementers trying to make sense of it every other day).