Generator issue: exceptions while initializing arguments

Dmitry Soshnikov dmitry.soshnikov at
Thu Sep 13 17:17:28 PDT 2012

On Wed, Sep 12, 2012 at 5:13 AM, Brendan Eich <brendan at> wrote:

> You say it's too error prone but you don't adduce any evidence.
> Meanwhile we have lots of extant code that does things like
>   function foo(bar, baz) {
>     baz = baz || default_baz;
>     ...
>   }
> That's the cowpath we are paving.

I see. Although, I cannot recall any other language which uses complex
expressions (such as function calls, or even referencing to the neighbor
parameters) for defaults. Usually they are just literals (no matter which,
primitive or objects -- they are recreated every time at activation).

But, I agree, they way you describe brings more power, and maybe JS will be
the first language with such semantics for defaults.

If so, then it's just the matter of the specification to notice all the
subtle cases.

function getDefaul() {}

function foo(bar = [], baz = bar, quz = getDefault()) {
  function getDefault() {}

The first thing which will confuse the devs is that `getDefault()`
expression is not the immediate function call to only _initialize_ the
default value of "quz", but is the syntactic form of calling this function
every time to calculate the default value. This should be mentioned very
explicitly, because from the top-down code viewing it really looks like
getDefault() is just an initialize of the default, and in this view, its
scope is even looks like the outer scope.

Second, of course the scope of all the defaults expressions, with the bold
font: "Notice, that the scope of defaults evaluation is the body of the
function. This is done to support referencing to the neighbor arguments".

As for generators,

function createGen(foo = thrower()) {
  yield 1;

var gen = createGen(); // loc1; // loc2

Of course the devs (again, w/o referencing to spec or detailed docs), would
expect that the "thrower()" is called right away when the "createGen"
function is defined. After they have read the docs, and now know that such
function calls are executed at function activation instead, they would
expect that the "thrower()" is called at "loc1", when the function is
activated to create the generator object.

OTOH, we understand the technical implementation, that the call to
"createGen" may not execute the function body, and therefore, not to call
"thrower()". And this is again will be too confusing for novices (?) that
it (by the technical details/implementation?) should/may be an "loc2".

So, if all these things described above are worth
doing/supporting/explaining/etc., then we can build defaults based on "foo
= foo || bar()" pattern which is used today. Then it's completely OK, I
agree, it's powerful.

However, if to take new programmers which will join JS from now,
potentially they should not know about old patterns for defaults as "foo =
foo || default", and they can use simple defaults as literals only.

In some/many languages the defaults are used with `null`s only to be able
to call a function with lesser parameters number. E.g. (PHP):

function foo($foo, $bar = null) {
  if (!$bar) {
    $bar = $this->getDefault();

And now they can use foo(10), or foo(10, "bar"); But still, the expression
which calculates the default $bar is described explicitly inside (in the
scope of) the function.

JS has no such problems, we may call foo(), or foo(10), or foo(10, "bar")
regardless default values, even today.

Also, the fact, that the expressions should be calculated at activation,
not creation, comes from legacy, when function declarations should be
created on entering the context. Then, even this code:

var foo = function () {};

function bar(baz = foo()) {

Should not logically work, since "bar", being a FD, is created on entering
the context, when "foo" is not function yet. This can satisfy the
activation frame + activation time rules for such expressions.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list