undefined being treated as a missing optional argument

Allen Wirfs-Brock allen at wirfs-brock.com
Wed Apr 11 22:28:48 PDT 2012


On Apr 11, 2012, at 7:01 PM, Luke Hoban wrote:

>>> Just to start, it means a method like:
>>>  Array.prototype.fill = function(value=null) { this.forEach((v,i)=>this[i]=value)}
>>> wouldn't do the obvious thing when called as:
>>>  someArray.fill(undefined)
> 
> I think it is debatable what is obvious in this case.  The wiki says that this should fill the array with 'undefined' (I believe the spec draft aims to say the same, but I can't tell where this is established).

The same runtime semantics routines are used for both default parameter initialization and for initializing array destructurings in let/const declarations (and hence same semantics for places).  For formal parameters it starts in the Runtime Semantics of 13.1 and (in theory) for individual formal parameters of the form (id=expr) will eventually reach Keyed Binding Initialisation for the production singeNameBind : BindingIdentifier Initialiser in 12.2.4.  It's "in theory" because it looks like the current draft is missing a couple intermediate steps in 13.1.

>  But I think many JavaScript developers would expect this to fill the array with 'null'.
> 
> Some arguments in favor of for treating undefined the same as not-present:
> 
> 1) Existing uses of default value patterns in JavaSscript use undefined as the sentinel for not present, so a semantics for default values in ES6 that behaves differently will not be usable as a shorthand for any of these existing APIs without changing semantics.

Undefined is not always such a sentential.  Some examples of built-ins that treat undefined different form a missing parameter:

  function(a){return a}.bind(null)
vs
  function(a){return a}.bind(null)

  new Array()
vs
  new Array(undefined)

  [].reduce(function(){})
vs
  [].reduce(function(){},undefined)

  new String()
vs
  new String(undefined)

  Number()
vs
  Number(undefined)

   new Date(2012,3)
vs
   new Date(2012,3,undefined)

etc.

I suggest that the appropriate way to think of about the current behavior, in the context of ES6, is that
   function f(a) {...}
is equivalent to
   function f(a=undefined) {...}

In other words, there is a default initialization expression, if one is not specified. So, f() and f(undefined) appear to produce the same result.  But I see why somebody calling a function defined as
  function(a={ }){...}
explicitly as f(undefined) would expect to trigger the default  value initializer.


> 
> 2) The fact that JavaScript (at least for user objects) currently doesn't differentiate between missing arguments and undefined arguments is a nice simplifying rule in the language that is easy to understand..

It does differentiate, at least in regard to the arguments object.  Consider:

  function f(a,b,c) {
     console.log(arguments.length);
     a="modified";
     console.log(arguments[0])
   }
  f();
  f(undefined); 

Which for Es5 produces:
0
undefined
1
modified

> 
> 3) The example above, of wanting to have an API that allows explicitly passing in undefined to override a default value, seems outside of the common case (out of curiosity - are there any realistic example of this?).  If truly desired, it is easy to not use default values.  But the common case seems more likely to be to emulate what is done today - and avoid having any undefined values flow into the API call.

Why is the example, outside of common sense.  It is a straightforward function to fill every element of an array with a common value. Undefined is certain something that can be stored in arrays so why wouldn't there be situations where where you would want to pass undefined.  Particularly if the fill function was written by an unreformed Java programmer who used a peculiar default fill value.

I agree that there is some confusion among some JS programmer about the current missing argument default value rules.  However, I don't think what you are suggesting is going to reduce that confusion.  I think it will increase it. 

Allen


> 
> Luke
> 
> 
> 

  function(a){return a}.bind(null)



More information about the es-discuss mailing list