« ECMAScript 4th Edition Vectors Proposal Draft 1 | Main | ECMAScript 4 Edition Progress Spreadsheet »

Proposed ... (splat) operator in ECMAScript 4th Edition allows easy pass-through of rest arguments to super constructor.

Recently, Brendan Eich added a new trac ticket that proposes a new operator, ... (informally called "splat"), for ECMAScript 4th edition. The fate of this ticket is currently unknown, but I really like this proposal because it solves a thorny issue I've had when trying to pass ...rest arguments to a super constructor in ActionScript 3.0. I'll get back to that problem in a minute, but first I want to draw a clear distinction between the proposed ... (splat) operator and the ... (rest) parameter that many of you have probably used in ActionScript 3.0.

In case you don't know, ActionScript 3.0 has a ... (rest) parameter that you can use to specify that a function accepts a variable number of arguments. For example, the Array.push() method uses the rest parameter to signify that it accepts a comma-separated list of arguments:

The ... (splat) operator complements the rest parameter by allowing you to send an array of values as arguments to a function when you don't know ahead of time what the length of that array will be at runtime. In other words, you use the rest parameter when you define what a function will accept as arguments and you use the splat operator when you are actually sending arguments during a function call. Now let's take a quick look at the major use case that the splat operator addresses.

Let's say you have a base class with a constructor that uses a rest parameter. You then create a subclass with a constructor that also uses a rest parameter. How do you pass the arguments from the subclass's constructor to the superclass's constructor? Let's see what happens when we do that:

Note that in the constructor for Base, I trace only the first element of the args array. When I create an instance of Base and pass in the list of numbers 1, 2, 3, the constructor converts the arguments into an array of three elements. However, when I create an instance of Extender with that same list of numbers, they end up bunched together as an array in the first element of the args array in the Base constructor. Unfortunately, in ActionScript 3.0 you cannot use Function.apply() to call the super constructor. There is currently no simple way in ActionScript 3.0 to pass through the arguments to the super constructor and have the arguments treated the same way whether they come from a direct instantiation of Base or through a call to super() from Extender.

The proposed ... (splat) operator solves this problem by allowing simple pass-through of rest arguments using the following new syntax:

Here's a list of relevant links:

Comments

Hi,
the idea is great. But something confuses me:

public function Extender (... args) : super(... args) {
This new notation for calling super. How would this look like for a normal method that has a return type? Like this?
public function doSomething(...args) : super(...args) : int {

I would very much like to have this operator as I've been running up against this issue repeatedly.

This would be a welcome inclusion to the language.
As a workaround we currently use a switch statement in order to determine the arguments lengths and call new Foo() with the correct amount of arguments.

Are there any plans on how to add compile time checking for datatypes?
Could function Foo(...rest:<typedarray>) : super(...rest<typedarray>) { be possible.

Hi Sven,

The new notation for calling super is called an "initializer" and it can only be used in the "head" of a constructor. In other words, you can't use this technique in a normal method, though you can still use the splat operator in a normal method when calling super, you'd just have to call super() from the body of the function instead of the head/initializer.

Francis

"though you can still use the splat operator in a normal method when calling super, you'd just have to call super() from the body of the function instead of the head/initializer."

I'm a little confused at how this would look? If the super is in the body, I don't see any difference to what we current have. Can you clarify how we can distinguish between them? i.e. this is what we do now, and the super would get 1 argument. Can you show an example of what the use of the splat operator would look like in this case.

override public function doSomething(...args) :int
{
return super(...args);
}

Also once I understand how the above question works, why does the constructor have to work in a different way? Wouldn't it make sense for it to always be used in the body?

That's pretty close, Tink, but you'd have to call the super function by name:

// Proposed ES4
override public function doSomething(...args) :int
{
return super.doSomething(...args);
}

You can't do this in ActionScript 3.0. The closest you can get is Function.apply():

// Current ActionScript 3.0
override public function doSomething(...args) :int
{
return super.doSomething.apply(this, args);
}

So it doesn't add any new functionality for this use case, but you can't use apply() to call a super constructor, so the splat operator would be helpful if you want to call a super constructor.

So why does the constructor have to work a different way? Well, that's a long story. It starts with ES4's new nullability proposal, which allows you to make a variable non-nullable. The problem is that the default value of a variable is usually null, so in some cases you could end up with non-nullable variables with no default value. User code that encounters such a variable (with no value) would be very unhappy. So ES4 requires that all non-nullable variables be initialized before they are used. To accomodate this requirement, ES4 adds a new initializer capability to constructor declarations that allows you to initialize variables before entering the constructor body.

Given that sometimes the super constructor will be responsible for initializing a non-nullable variable, ES4 also makes it possible to call the superconstructor from the initializer. So to sum up, you may be able to call super(...args) from the constructor body, but you can also use the initializer to ensure that any non-nullable variables are properly initialized. It seems easier to get in the habit of calling super() in the initializer.

Wo kann ich die Software downloaden?

You are not obliged to call super() in the first line of the constructor, more than that, sometimes you don't do it on purpose, like in case you want to alter some protected variable's value before executing superclass constructor. So, making the call to the superclass constructor a mandatory first line is a regression to AS2... I was thinking about notation similar to PHP, so, say, you may have an operator replacing for-each loop like this:

public function TheConstructor(...rest)
{
super(rest=>value);
}
which would mean it iterates through the values of an array and pushes them into function arguments.

It makes perfect sense that the rest parameter has a reciprocal usage.
If it gets adopted perhaps I'll implement the splat in JASPA : http://jaspa.org.uk/wiki/Rest_args

Post a comment