dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.23k stars 1.57k forks source link

Support Python-like negative indexes on indexed collections-like objects #52771

Open mateusfccp opened 1 year ago

mateusfccp commented 1 year ago

The decade-long issue #983 suggests adding Python-like slices to Dart. Although it's somewhat related with negative indexes in collections, and some commenters in the issue talked about it, I see it as a separate feature, and thus I'm opening another issue.

Basically, negative indexes works like regular indexes but starting at the end.

So, for instance, if I want to get the 2nd last element of a List, instead of using list[list.length - 2] I could use list[-2].

This could be extended not only to [] but other methods, like sublist or substring:

final str = 'banana';
final nana1 = str.substring(str.length - 4);
final nana2 = str.substring(-4);

Note that, in addition to being shorter, in the second case we wouldn't have the need to bind the string to str, as we wouldn't have the need to access it's length.

AFAIK this can already be implemented, as the [] operator on Lists/Strings already accept negative numbers, but throws a RangeError in runtime, thus there's no need for changes in the language.

Cons

A possible con is that when someone uses computed indexes, in many cases computing negative indexes would not be intended. Thus, the user would either have to manually check for negative indexes or it would result in a non-error in runtime that could pass unnoticed.

lrhn commented 1 year ago

We've delibearately chosen to not support negative indices.

The main reason is that it's error-prone. If you accidentally subtract too much from an index, instead of getting an error, it just reads from somehwere else in the same list.

If we had a shorter way to say string.length - n, it would probably not be as jarring. The double occurrence of string in string.substring(string.length - 4) is what makes string.substring(-4) look so much nicer. But I don't think it's worth the missed-error potential.

A str.substringFromEnd(-4) would be less problematic. It'd require an arugment in the range -length..0 (both inclusive). That makes it better than just using substring, because you can do str.substringFromEnd(-requiredLength) without worrying that requiredLenght is zero and you get the whole string instead of no string. In the "banana" example code here, if the -4 had been a variable, -tailLength, and tailLength ended up as zero, the two lines wouldn't do the same thing. (And we don't want to recognize -0 as different from 0, even if JS could do that.)

We could add such a method, but it's also not that big a priority, just a convenience.

gerrywastaken commented 1 month ago

@lrhn

If you accidentally subtract too much from an index, instead of getting an error, it just reads from somehwere else in the same list.

The same is true even if you don't exceed the bounds. You can end up reading an extra character or less characters than you intended to. If you are worried about a loop where you are doing index - 1 then you would end up exceeding the bounds either way if you do not stop where intended.

I think negative indexing makes the syntax more intuitive, which leads to less errors.