@@iterator in arguments object

# Nathan Wall (12 years ago)

I never fully understood why the arguments object couldn't be an array, and I know there is at least an attempted purge of the arguments object from the language with the addition of rest parameters.. But, for the transitional period, can the arguments object have an @@iterator property?  Please??

(I looked for it in the draft and didn't see it, but I might not have known where to look.)

Nathan

# Rick Waldron (12 years ago)

On Sat, Dec 22, 2012 at 4:57 PM, Nathan Wall <nathan.wall at live.com> wrote:

I never fully understood why the arguments object couldn't be an array, and I know there is at least an attempted purge of the arguments object from the language with the addition of rest parameters.. But, for the transitional period, can the arguments object have an @@iterator property? Please??

Yes

(I looked for it in the draft and didn't see it, but I might not have known where to look.)

Likely because Allen had enough on his plate for this draft, but there is already a ticket based on a resolution from the last TC39 meetng: ecmascript#1114

# Nathan Wall (12 years ago)

That's great news! Thank you!

Nathan

# Brandon Benvie (12 years ago)

It's good this will be added (no reason not to) but I'll note that is much less of a requirement to even use the arguments object at all, especially iteration use cases that are pretty much filled by rest. In fact (almost?) the only place I've actually referenced the arguments object is to count the number of arguments to differentiate between deliberate undefined and a missing argument (and only for that use in order to match the behavior of how js engines treat the arguments to some string built-ins).

# Axel Rauschmayer (12 years ago)

Parameter default values weren't good enough for this?

[[[Sent from a mobile device. Please forgive brevity and typos.]]]

Dr. Axel Rauschmayer axel at rauschma.de Home: rauschma.de Blog: 2ality.com

# Brandon Benvie (12 years ago)

You're right, defaults would take care of those few places reducing the need to reference the arguments object entirely. I think there may be one or two exceptions, like when there's no default value but an explicit undefined is coerced to "undefined" but a lack of the argument becomes an empty string. I guessable default value of the empty string may cover this but I have a nagging feeling there's some exception in one of the builtin methods that defies all attempts that don't rely on arguments.length, but I can't figure out what that method might be.

# Brendan Eich (12 years ago)

Brandon Benvie wrote:

You're right, defaults would take care of those few places reducing the need to reference the arguments object entirely. I think there may be one or two exceptions, like when there's no default value but an explicit undefined is coerced to "undefined" but a lack of the argument becomes an empty string. I guessable default value of the empty string may cover this but I have a nagging feeling there's some exception in one of the builtin methods that defies all attempts that don't rely on arguments.length, but I can't figure out what that method might be.

If it exists, it's just bad precedent.

You could always use an explicit rest parameter as the only formal parameter and still dispense with arguments in new code. So let's say s/could/should/.

# Brandon Benvie (12 years ago)

Yeah good point, and you don't even need to dump all the named params. In light of this, I think its feasible to pronounce the arguments object in ES6 as vestigial and ready for retirement (except for all the legacy code of course). ES6 claims another victim: [object Arguments].

# Allen Wirfs-Brock (12 years ago)

On Dec 23, 2012, at 9:38 AM, Brendan Eich wrote:

Brandon Benvie wrote:

You're right, defaults would take care of those few places reducing the need to reference the arguments object entirely. I think there may be one or two exceptions, like when there's no default value but an explicit undefined is coerced to "undefined" but a lack of the argument becomes an empty string. I guessable default value of the empty string may cover this but I have a nagging feeling there's some exception in one of the builtin methods that defies all attempts that don't rely on arguments.length, but I can't figure out what that method might be.

If it exists, it's just bad precedent.

You could always use an explicit rest parameter as the only formal parameter and still dispense with arguments in new code. So let's say s/could/should/.

And you can then use destructuring assignment to parse out that rest parameter into one or more signature patterns.

# Wes Garland (12 years ago)

Arguments object is used here to fill the rest void, but also as an argument to apply (after converting into a real array) when writing wrapper functions; eg monkey patches, userspace profiling, etc.

Is there an ES6 way to use apply on rest params? If not, arguments must live on.

Sent from my iPhone

On 2012-12-23, at 12:48, Brandon Benvie <brandon at brandonbenvie.com> wrote:

Yeah good point, and you don't even need to dump all the named params. In light of this, I think its feasible to pronounce the arguments object in ES6 as vestigial and ready for retirement (except for all the legacy code of course). ES6 claims another victim: [object Arguments].

# Brandon Benvie (12 years ago)

Something like this?

var partial = (fn, ...args) => function(...newArgs){ return fn.apply(this, args.concat(newArgs)); };

# Brendan Eich (12 years ago)

Wes Garland wrote:

Arguments object is used here to fill the rest void, but also as an argument to apply (after converting into a real array) when writing wrapper functions; eg monkey patches, userspace profiling, etc.

Is there an ES6 way to use apply on rest params?

A rest parameter is a real Array instance. Function.prototype.apply works on array instances. What's the problem?

# Allen Wirfs-Brock (12 years ago)

As of ES5, apply doesn't require its 2nd arg to be a "real array". An arguments object works fine there.

# Brandon Benvie (12 years ago)

Here's one of the examples that was sticking out in my mind earlier that Brendan's solution takes care of. Array.prototype.reduce requires that if the initial value isn't provided then the first value of the array is the initial value.

Using rest:

function reduce(callback, ...initial){
  var current, index;

  if (initial.length) {
    index = 0;
    current = initial[0];
  } else {
    index = 1;
    current = this[0];
  }

  ...etc...
}

Using arguments.length:

function reduce(callback, initial){
  var current, index;

  if (arguments.length > 1) {
    index = 0;
    current = initial;
  } else {
    index = 1;
    current = this[0];
  }

  ...etc...
}

I guess using rest like that is not a bad way to solve it, though it's not saying what you mean but rather kind of hacking around the limitation. Either way, it's certainly possible to forgo using arguments to accomplish the goal.

# Jason Orendorff (12 years ago)

On Sun, Dec 23, 2012 at 1:26 PM, Wes Garland <wes at page.ca> wrote:

Arguments object is used here to fill the rest void, but also as an argument to apply (after converting into a real array) when writing wrapper functions; eg monkey patches, userspace profiling, etc.

Is there an ES6 way to use apply on rest params? If not, arguments must live on.

There is something really nice. You can use the ... operator when calling a function. For example, if you're wrapping a function foo:

_origFoo = foo; foo = function (a, b, ...rest) { // ... do something ... return _origFoo(a, b, ...rest); };

If you're wrapping a method it's not quite as nice, but:

_origMethod = Bar.prototype.method; Bar.prototype.method = function (a, b, ...rest) { // ... do something ... return _origMethod.call(this, a, b, ...rest); };

# Rick Waldron (12 years ago)

On Sun, Dec 23, 2012 at 8:35 PM, Brandon Benvie <brandon at brandonbenvie.com>wrote:

Here's one of the examples that was sticking out in my mind earlier that Brendan's solution takes care of. Array.prototype.reduce requires that if the initial value isn't provided then the first value of the array is the initial value.

Using rest:

function reduce(callback, ...initial){
  var current, index;

  if (initial.length) {
    index = 0;
    current = initial[0];
  } else {
    index = 1;
    current = this[0];
  }

  ...etc...
}

Using arguments.length:

function reduce(callback, initial){
  var current, index;

  if (arguments.length > 1) {
    index = 0;
    current = initial;
  } else {
    index = 1;
    current = this[0];
  }

  ...etc...
}

I guess using rest like that is not a bad way to solve it, though it's not saying what you mean but rather kind of hacking around the limitation. Either way, it's certainly possible to forgo using arguments to accomplish the goal.

In the case of reduce, the specification algorithm names an identifier in the formal parameter list: initialValue, so what is preventing your implementation from doing initial !== undefined?

# Brandon Benvie (12 years ago)

Because initialValue can be a provided undefined in which case you would use that, as opposed to a missing value. The specification differentiates between a provided undefined and a lack of a parameter in a bunch of stdlib functions/methods.

# Brandon Benvie (12 years ago)

Er missing argument. The spec says "If an initialValue was provided in the call to reduce, ...". The fact that undefined is different from "not provided" is the reason you have to hack around with the argument count one way or another.

# Allen Wirfs-Brock (12 years ago)

On Dec 23, 2012, at 5:35 PM, Brandon Benvie wrote:

Here's one of the examples that was sticking out in my mind earlier that Brendan's solution takes care of. Array.prototype.reduce requires that if the initial value isn't provided then the first value of the array is the initial value.

Using rest:

function reduce(callback, ...initial){
  var current, index;

  if (initial.length) {
    index = 0;
    current = initial[0];
  } else {
    index = 1;
    current = this[0];
  }

  ...etc...
}

Using arguments.length:

function reduce(callback, initial){
  var current, index;
  
  if (arguments.length > 1) {
    index = 0;
    current = initial;
  } else {
    index = 1;
    current = this[0];
  }

  ...etc...
}

I guess using rest like that is not a bad way to solve it, though it's not saying what you mean but rather kind of hacking around the limitation. Either way, it's certainly possible to forgo using arguments to accomplish the goal.

the way I would express this example is:

function reduce(callback, ...rest){ var current, index; if (rest.length > 0) { index = 0; current = rest[0]; } else { index = 1; current = this[0]; } ...etc... }

which seems to exactly express the intent

# Rick Waldron (12 years ago)

On Sun, Dec 23, 2012 at 9:25 PM, Brandon Benvie <brandon at brandonbenvie.com>wrote:

Because initialValue can be a provided undefined in which case you would use that, as opposed to a missing value. The specification differentiates between a provided undefined and a lack of a parameter in a bunch of stdlib functions/methods.

True enough: "is present", used in reduce, reduceRight, Object.create and then elsewhere in the abstract internals and then in different contexts.

# Axel Rauschmayer (12 years ago)

How about the following solution?

let missingArgument = {}; // or a symbol
function reduce(callback, initial = missingArgument){
    let startIndex;
 
    if (initial === missingArgument) {
        initial = this[0];
        startIndex = 1;
    } else {
        startIndex = 0;
    }
 
    ...etc...
}
# Brandon Benvie (12 years ago)

That is an excellent solution!

# Axel Rauschmayer (12 years ago)

Thanks. The first let should be a const.

# Allen Wirfs-Brock (12 years ago)

Won't work for an explicitly pass undefined because that triggers assignment of the default value

# Brandon Benvie (12 years ago)

Ah yes, so default value can't do the job in any case where undefined is differentiated from missing, similar to how directly comparing the named binding to undefined can't differentiate either.

# Axel Rauschmayer (12 years ago)

Ah damn, forgot about that discussion (combinatorial explosion etc.).

# Allen Wirfs-Brock (12 years ago)

Welcome to my life...

# Rick Waldron (12 years ago)

On Sun, Dec 23, 2012 at 10:46 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

How about the following solution?

let missingArgument = {}; // or a symbol
function reduce(callback, initial = missingArgument){
    let startIndex;

An explicit undefined will trigger the default value, in this case resulting in the missingArgument to be used

See: esdiscuss/2012-July/024207