What does "is not present" mean in spec algorithms?

# Boris Zbarsky (10 years ago)

Consider people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.splice step 10. It uses the phrasing "if deleteCount is not present" but I can't find anything in the specification defining the concept of "present" or "not present". So it's hard for me to tell what behavior this is actually defining.

Is this supposed to be a typeof(deleteCount) == "undefined" test, an argc test, or something else?

I'm assuming it's supposed to be the typeof() == "undefined" test, but this should actually be specified somewhere. Perhaps as a definition in section 4.3?

# Allen Wirfs-Brock (10 years ago)

Nope, it means that the length of the argument list is less than two, hence an argument corresponding to 'deleteCount' was not passed.

people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-standard-built-in-objects (para 4) says: "Unless otherwise specified in the description of a particular function, if a built-in function or constructor is given fewer arguments than the function is specified to require, the function or constructor shall behave exactly as if it had been given sufficient additional arguments, each such argument being the undefined value."

So, "is not present" is how handling of missing arguments is "otherwise specified".

If the algorithm need to simply test for an explicitly or implicitly passed undefined, it would simply say "If argument is undefined, then ..."

I always thought "not present" was sufficiently descriptive, in combination with the missing args default to undefined rule, that it didn't need further definition.

# Brendan Eich (10 years ago)

On Feb 20, 2014, at 8:16 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Nope, it means that the length of the argument list is less than two, hence an argument corresponding to 'deleteCount' was not passed.

people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-standard-built-in-objects (para 4) says: "Unless otherwise specified in the description of a particular function, if a built-in function or constructor is given fewer arguments than the function is specified to require, the function or constructor shall behave exactly as if it had been given sufficient additional arguments, each such argument being the undefined value."

Note lack of the words "not" and "present" above,

So, "is not present" is how handling of missing arguments is "otherwise specified".

If the algorithm need to simply test for an explicitly or implicitly passed undefined, it would simply say "If argument is undefined, then ..."

I always thought "not present" was sufficiently descriptive, in combination with the missing args default to undefined rule, that it didn't need further definition.

Why? Those words do not occur in the rule's definition.

# Allen Wirfs-Brock (10 years ago)

That's one of the strengths/weaknesses of pseudo code. It's not manageable to formally define phrase so you depend upon commonly understood the natural language meaning for a lot of things.

But, I rule of thumb is that if one person is vocal about being confused then many other also probably are.

Boris should file a bug.

# Boris Zbarsky (10 years ago)

On 2/20/14 11:16 AM, Allen Wirfs-Brock wrote:

Nope, it means that the length of the argument list is less than two, hence an argument corresponding to 'deleteCount' was not passed.

OK. In that case, I think this term really needs to be defined. Ideally with links to the definition whenever it's used.

So, "is not present" is how handling of missing arguments is "otherwise specified".

This is really confusing action-at-a-distance that I think we should make more explicit. At the very least, something needs to make it clear that an "is not present" test is in fact an "otherwise specified" for purposes of this section.

I always thought "not present" was sufficiently descriptive, in combination with the missing args default to undefined rule, that it didn't need further definition.

It's confused at least me and one other person so far...

# Boris Zbarsky (10 years ago)

On 2/20/14 12:09 PM, Allen Wirfs-Brock wrote:

Boris should file a bug.

Done. ecmascript#2559

Thanks, Boris

# Rick Waldron (10 years ago)

On Thu, Feb 20, 2014 at 12:11 PM, Boris Zbarsky <bzbarsky at mit.edu> wrote:

It's confused at least me and one other person so far...

You're not alone: esdiscuss/2013-May/030928

# Allen Wirfs-Brock (10 years ago)

On Feb 20, 2014, at 9:11 AM, Boris Zbarsky wrote:

On 2/20/14 11:16 AM, Allen Wirfs-Brock wrote:

Nope, it means that the length of the argument list is less than two, hence an argument corresponding to 'deleteCount' was not passed.

Would you prefer it to say "If fewer than two arguments were passed, then let deleteCount be ..."?

Even when phrases like"not present" are formally defined, many people don't actually read those definitions and it is vary hard to maintain explicit cross reference to many such phrases. That's why I prefer self apparent natural language phrasing, where possible.

OK. In that case, I think this term really needs to be defined. Ideally with links to the definition whenever it's used.

So, "is not present" is how handling of missing arguments is "otherwise specified".

This is really confusing action-at-a-distance that I think we should make more explicit. At the very least, something needs to make it clear that an "is not present" test is in fact an "otherwise specified" for purposes of this section.

Actually saying anything rather than just using the value is "otherwise specifying"

# Boris Zbarsky (10 years ago)

On 2/20/14 12:24 PM, Allen Wirfs-Brock wrote:

Would you prefer it to say "If fewer than two arguments were passed, then let deleteCount be ..."?

That would be clearer, yes, if we want to stick to natural language here. It avoids confusion about undefined == missing issues, for sure, and makes it clear what an implementation would actually be testing.

# C. Scott Ananian (10 years ago)

I wasn't confused by the spec text as is, but I'm not surprised that others are. The language is battling against two different "standards" for optional arguments. In ES5 typically "not present" is used; in ES6 for consistency with the new language optional arguments, "undefined" is treated as "not present" and arguments.length is ignored.

This issue arose in a discussion with the bluebird maintainer about the proper semantics for Promise.reduce; he wanted to use "ES6 style" for the final optional argument (which meant that you can't use undefined as an initialValue), while I wanted "ES5 style" to be consistent with the ES5 method Array#reduce.

It might be worth coming up with good terms for "ES5-style optional arguments" and "ES6-style optional arguments" which can be used consistently in the spec. They can already be distinguished by signature, ie:

Array.prototype.reduce ( callbackfn [ , initialValue ] )
Array.prototype.splice (start, deleteCount [ , item1 [ , item2 [ , … ] ] ] )

versus

Array.prototype.fill (value, start = 0, end = this.length)
Array.prototype.copyWithin (target, start, end = this.length)

Another alternative might be to define a helper function used wherever "ES5-style" optional arguments were used.

On the gripping hand, ES5-style optional arguments are actually more similar semantically to ES6 'rest' arguments; perhaps the spec can be written to use a rest argument. For example:

Array.prototype.splice (start, deleteCount, ...items) // like in the
signature for Array.of()

ps. esdiscuss.org/topic/changing-behavior-of-array-copywithin-when-used-on-array-like-with-negative-length

# Allen Wirfs-Brock (10 years ago)

On Feb 21, 2014, at 1:47 PM, C. Scott Ananian wrote:

I wasn't confused by the spec text as is, but I'm not surprised that others are. The language is battling against two different "standards" for optional arguments. In ES5 typically "not present" is used; in ES6 for consistency with the new language optional arguments, "undefined" is treated as "not present" and arguments.length is ignored.

This really isn't correct. It has always been the case that arguments that are not explicitly included in the actual argument list are automatically initialized to undefined. Most spec. (ES3, ES5, Es6, etc.) references to arguments simply reference them by name and don't worry about whether or not an argument has the value undefined because it was explicitly passed by the called or if it was default to undefined by the language semantics.

There are a few functions and methods, some of them dating back to least ES3 that treat a explicit undefined value differently from a missing argument value. In ES5 "in pressent" or "not passed" is used to explicitly identify such cases.

There are also few places where either the ES3 spec. did not match the web reality that browsers have implemented for situations where argument values were not explicitly passed.. Most of those were corrected in ES5, ES6 makes a fix in this regard for Array.prototype.splice. Compare people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.splice to the definition in ES5 and not that ES5 does not have the equivalent to steps 9 and 10.

There is no general change of style for new ES6 built-in regarding the handling of arguments that are not explicitly passed and the specification of built-in methods do not depend upon default parameter value initialization (that's a ES language feature but built-ins are not necessarily implemented using ES). There are cases where ES6 parameter default value initialization an be used to describe the legacy behavior but that isn't a change of behavior from ES5 or ES3.

This issue arose in a discussion with the bluebird maintainer about the proper semantics for Promise.reduce; he wanted to use "ES6 style" for the final optional argument (which meant that you can't use undefined as an initialValue), while I wanted "ES5 style" to be consistent with the ES5 method Array#reduce.

If Proimise.reduce is supposed to be similar to Array.prototype.reduce then I'd recommend using exactly the same argument conventions for.

It might be worth coming up with good terms for "ES5-style optional arguments" and "ES6-style optional arguments" which can be used consistently in the spec. They can already be distinguished by signature, ie:

Array.prototype.reduce ( callbackfn [ , initialValue ] )
Array.prototype.splice (start, deleteCount [ , item1 [ , item2 [ , … ] ] ] )

versus

Array.prototype.fill (value, start = 0, end = this.length)
Array.prototype.copyWithin (target, start, end = this.length)

Don't put too much weight into that. I've experiment with use the latter style when define some new methods to see where it is helpfully more descriptive. I just haven't bother to update all the legacy methods to use that same style. At some point in the near future I wall make a pass over the entire document and use consistent conventions for all function signatres -- either the ES3/5 style or the default value style. Given the amount of confusion the new style seems to have case, I may well revert to using the ES3/5 style.

Another alternative might be to define a helper function used wherever "ES5-style" optional arguments were used.

I summary, there is no actual differences in style. ES functions have always used undefined as the default value of formal parameters that do not have an explicit corresponding actual argument in the call. Functions that what to provide some other treatment for such missing arguments have always had to deal with that situation explicitly.

All Es6 really adds in this regard is a short and for saying: if (parameterN===undefined) paramaterN=expr;

# Brandon Benvie (10 years ago)

On 2/21/2014 3:08 PM, Allen Wirfs-Brock wrote:

Don't put too much weight into that. I've experiment with use the latter style when define some new methods to see where it is helpfully more descriptive. I just haven't bother to update all the legacy methods to use that same style. At some point in the near future I wall make a pass over the entire document and use consistent conventions for all function signatres -- either the ES3/5 style or the default value style. Given the amount of confusion the new style seems to have case, I may well revert to using the ES3/5 style.

Isn't there a problem with the new contention because some steps are either implicit or aren't done? For example, end = this.length in the ES5 style would have explicit ToObject conversion on this before getting its length.

# Allen Wirfs-Brock (10 years ago)

Right, my intend wasn't that those signature should ever be read as in any way normative. The actual algorithm steps always explicitly describe the parameter defaulting behavior when it is anything other than just use undefined.

Formerly we just would have used a signature heading like:

Array.prototype.fill (value [, start [, end]])

it was hoping that something like

 Array.prototype.fill(value, start=0, end=this.length)

would be more usefully informative.

But in neither case is such a heading line intended to be an normative definition or syntactically valid JS code.

# Brendan Eich (10 years ago)

No informative deed goes unpunished, especially (as in this case) if it has contradictory normative implications! This was the lesson of ECMA-357 (E4X), with its overdone informative prose which often contradicted the normative prose.