Proposal: Array.prototype.last()

# Jordan Osete (14 years ago)

Hello everybody.

I've been wondering for some time if there couldn't be a way to index arrays from the last element directly. Currently if you have an array lost in a deep objects hierarchy, you have to refer to it twice, once to access the array itself, and once again to access its length:

var lastItem = myObject.anArray[ myObject.anArray.length - 1 ]; myObject.anArray[ myObject.anArray.length - 2 ] = "foo";

As it seems hard to change the core language to be able to access stuff with negative indexes, the idea would be just to add a method to ease getting / setting of items based on the length of the array:

//get the last element, same as .last( 0 ) var lastItem = myObject.anArray.last(); //set the ( length - 2 ) element myObject.anArray.last( 1, "foo" );

It can also be implemented with current UAs.

,

Jordan Osete

# Mike Shaver (14 years ago)

On Wed, May 5, 2010 at 8:27 AM, Jordan Osete <jordan.osete at yahoo.fr> wrote:

I've been wondering for some time if there couldn't be a way to index arrays from the last element directly. Currently if you have an array lost in a deep objects hierarchy, you have to refer to it twice, once to access the array itself, and once again to access its length:

A temporary helps here, as is often the case with deep hierarchies.

var lastItem =

myObject.anArray[ myObject.anArray.length - 1 ];

myObject.anArray[ myObject.anArray.length - 2 ] = "foo";

a = myObject.anArray; a[a.length - 1];

a[a.length - 2] = "foo";

As it seems hard to change the core language to be able to access stuff with negative indexes, the idea would be just to add a method to ease getting / setting of items based on the length of the array:

It would be incompatible, since a[-1] means the same thing for arrays as for objects: the property named "-1".

You can do it with slice and splice, though, if you don't want to just use a temporary:

//get the last element, same as .last( 0 )

var lastItem = myObject.anArray.last();

myObject.anArray.slice(-1)[0]

myObject.anArray.last( 1, "foo" );

myObject.anArray.splice(-2, 1, "foo");

With destructuring assignment, the slice usage gets to be a little more natural, though it still constructs an array unless there is some analysis done of the call site.

TBH, I don't think that end-based access to arrays other than to append, a la Array.prototype.push, is common enough to warrant adding to the language. You could decorate Array.prototype with your own |last| method (including the unusual get/set overload) if you wanted, and use ES5's property-descriptor facilities to keep it from affecting iteration.

Mike

# Biju (14 years ago)

var lastItem = myObject.anArray[ myObject.anArray.length - 1 ]; myObject.anArray[ myObject.anArray.length - 2 ] = "foo";

a = myObject.anArray; a[a.length - 1]; a[a.length - 2] = "foo";

What is the problem allowing following instead of above? a = myObject.anArray; a[-1]; a[-2] = "foo";

And I see, I can reduce a lot of my code if I can do a[ - a_var_with_postive_value] = "foo";

It would be incompatible, since a[-1] means the same thing for arrays as for objects: the property named "-1".

And I dont think any body depending on such code now, ie expecting "-1" as property name in Array

# Dmitry A. Soshnikov (14 years ago)

On 06.05.2010 10:06, Biju wrote:

var lastItem = myObject.anArray[ myObject.anArray.length - 1 ]; myObject.anArray[ myObject.anArray.length - 2 ] = "foo";

a = myObject.anArray; a[a.length - 1]; a[a.length - 2] = "foo";

What is the problem allowing following instead of above? a = myObject.anArray; a[-1]; a[-2] = "foo";

The problem is that currently ES has only concept a "property". And despite the fact that spec defines concept of an "array index", it still "virtual" concept and is only for ability to make some checks or actions (e.g. update "length" property with overloaded [[Put]] method). Still, these properties are only strings. And because of there is no semantic stratification between the dot and the bracket property accessor notations (except the the former is used only when property name is a valid identifier and in advance known), i.e. they are not divided into "keys" and "array indexes" for the bracket notation, and "properties" and "methods" for the dot notation, currently there is no ability to distinguish whether "-2" is a simple (or even inherited) property or means "length - 2" index.

Of course, there could be overloaded [[Get]] semantics for arrays, but this is not in ES5 (who's spec is already published and it's being implemented). The other questions should be clarified then, such as if there is e.g. Object.prototype[-3] = 10; and let a = [1, 2]; then what should return a[-3] if a[-2] returns 1. I.e. should be semantics of the arrays [[Get]] be completely overloaded and do not inherit such property names, or only partly (the last case will cause ambiguity).

But in general, bracket slicing (used widely in some languages) is more convenient than explicit "slice" method which does the same. But notice, that in contrast with ES in those languages there is stratification in semantics of the dot and bracket notations.

In contrast, proposed "last" method seems also ambiguous in case of setting and looks a bit ugly. That taking into account that there are method names with "get" semantics. So the setter "last(-index, value)" looks odd. So I don't think this proposal is very required. For convenience as maximum you can implement only a getter in the Array.prototype for just a.last.

It would be incompatible, since a[-1] means the same thing for arrays as for objects: the property named "-1".

And I dont think any body depending on such code now, ie expecting "-1" as property name in Array

I have had once upon a time ;)

Dmitry.

# Jordan Osete (14 years ago)

Sorry for this late answer. Using a temporary for this is not very convenient, it basically forces you to create an useless variable just for this purpose. The slice / splice solution is a little bit better, but i find it less clear, and more error prone.

Maybe the name "last" is not the best for this functionality, and also maybe it's not a good idea to use the same method for getting and setting (probably a jQuery habit). Still, indexing arrays from the end seems quite common for me.

What about some simple getItem( index ) / setItem( index, item ) variation ? More language-like and more convenient than the current solutions, they could easily be defined with slice- and splice-compatible behaviour:

Array.prototype.getItem = function (i) {return this.slice (i, 1)[0];}; Array.prototype.setItem = function (i, v) {this.splice (index, 1, [v]);};

,

Jordan Osete

# Dmitry A. Soshnikov (14 years ago)

On 12.05.2010 2:03, Jordan Osete wrote:

What about some simple getItem( index ) / setItem( index, item ) variation ? More language-like and more convenient than the current solutions, they could easily be defined with slice- and splice-compatible behaviour:

Array.prototype.getItem = function (i) {return this.slice (i, 1)[0];}; Array.prototype.setItem = function (i, v) {this.splice (index, 1, [v]);};

That's too bad concurrency for alternative and already invented syntactic sugar for that -- a bracket notation used in many languages. I should mention Python again and its very convenient indexing/slicing:

a[-1] # last a[2:5] # slice

Unfortunately (or fortunately -- it depends), repeat, ES has no semantic differentiation between dot and bracket notation. And that means the only way (to keep the common approach for bracket notation as just an alternative property accessory, but not for subscriptable objects). The only way to to do this is to overload also [[Get]] (with clarifying inheritance points of "-3" property from other link of the prototype chain).

And taking into account, that the main objective is backward compatibilities and decreasing of the new syntax, I'm not sure ES will do this. Although, it is of course convenient for exactly arrays.

And getItem / setItem in my opinion looks too "desugared" in era when many languages have the convenient sugar for that. Don't forget, that scripting language should be easy to use with elegant easy to write/remember and convenient constructions. From this viewpoint literary-like Java's style with its long complete "sentences" (long names) seems even less elegant.

So, don't think that JS -- a highly abstracted language, needs this getItem / setItems, even if for less abstracted languages (even for Assembler) there is bracket notation for addressing offset from the base of a structure.

Dmitry.

# Jordan Osete (14 years ago)

De : Dmitry A. Soshnikov <dmitry.soshnikov at gmail.com>

Envoyé le : Mer 12 mai 2010, 9h 12min 01s

That's too bad concurrency for alternative and already invented

syntactic sugar for that -- a bracket notation used in many languages. I should mention Python again and its very convenient indexing/slicing:

... So, don't think that JS -- a highly abstracted language, needs this

getItem / setItems, even if for less abstracted languages (even for Assembler) there is bracket notation for addressing offset from the base of a structure.

Well, I can agree of that, I would prefer to have that syntactic sugar. This kind of getItem / setItem would have been just temporary solutions for the current implementations until that sugar is ready to be used in a few years, just like filter and map are temporary replacements for array comprehensions.

Jordan

# Brendan Eich (14 years ago)

Agreed, we need a[-1] for a[a.length-1] syntactic sugar, or there's no
point. The Array slice method, among others, already does sensible and
Pythonic processing of negative arguments.

The way to provide syntax for negative indexes (if not Pythonic
slicing) is under a new version. But that would complicate the spec,
the various implementations, and the migration landscape for old code
(did this old code that I did not write, but that I'm paid to port,
use anything that evaluated to -1 as an array index?).

And such a strawman lacks a champion to write up the proposal and
carry it through prototyping and standardization. I've toyed with
slice syntax before, and may again, but I'm not that champion. So this
seems unlikely to make it past "straw" state.

# Biju (14 years ago)

On Wed, May 12, 2010 at 3:12 AM, Dmitry A. Soshnikov <dmitry.soshnikov at gmail.com> wrote:

a[2:5] # slice

This reminds me lack of a Range operator in javascript. The one like in Pascal and PL/SQL www.techonthenet.com/oracle/loops/for_loop.php Which can also be used in for loop

Many times when coding I need something like that in Javascript too And I suggest ... (three dots) as the operator because : has other uses in javascript and .. is used by E4X

Example usage are.

startIndex = 2;
lastIndex = 5;
myRange = startIndex ... lastIndex;
a[myRange]  // array slice

instead of if(a >= 2 && a <= 5) doSomething();

we could simplify code as if(a in 2 ... 5) doSomething();

or for(i in 2 ... 5) print(i);

we should also allow usage for Sting and Date range checking, like if('Dmitry' in 'Biju' ... 'Jordan') doSomething(); and if( (new Date(2010,1,1)) in (new Date(2008,1,1)) ... (new Date(2012,1,1))) doSomething();