0 1 2 3 4
-----------------
| A | B | C | D |
-----------------
-4 -3 -2 -1 -0
Except, of course, -0 doesn't exist. AFAIK that's why C# chose to add a special "index from end" operator, `^`, instead of using negative indices.Not for integers on modern hardware. If only hardware used ones’ complement (https://en.wikipedia.org/wiki/Ones'_complement)… ;-)
Meanwhile, the workaround is to use -1 through -5 to index from the end of the array.
Yes - personally, I do always count them left-to-right.
I don't think negative indices implies counting right-to-left. A negative step does, but I never use one because IMO it doesn't make sense to have an exclusive LHS and inclusive RHS.
It makes a little more sense if you have an array of something other than plain integers. Let's say you have 2-tuples:
0 1 2 3 4 5
| (0, 1) | (1, 1) | (1, 2) | (2, 3) | (3, 5) |
-5 -4 -3 -2 -1 -0
or perhaps a better display would be more memory-based, where a tuple is represented as a pair of bytes: 0 1 2 3 4 5
00010101010202030305
-5 -4 -3 -2 -1 -0
Now -3 clearly refers to the beginning of an array element. At least I wouldn't expect -3 to refer to (1, 1), even though I'm mentally traversing right to left for negative indexes.Or another way to think about it: arr[5] does not exist in the above example. It's the end of the array, and the end is exclusive. Negative indexes count from the end. -0, as a result, refers to the (unmodified) end, which is the nonexistent thing, same as arr[5].
And yet another way: think of positive indexes as going forward, negative as going back. Imagine a syntax arr[3][-2] where arr[3] gives you the subarray starting at offset 3. (In C or C++, this would be like (&arr[3])[-2] with an array type that supported negative indexes, which implies it tracks subarray length.) Where should you end up? Start with the simpler case of arr[3][-0] -- clearly that should be the same as arr[3], not arr[2], if you are "going back 0". And if you're starting out with 0-based indexes, then the "going forward"/"going back" interpretation is inescapable.
As a bonus, arr[-n] is the same as arr[arr.length() - n]. But that's just a lucky happenstance; I wouldn't argue that the semantics of negative indexes should depend on it. Well... one could argue that arr[arr.length()] is the (nonexistent, exclusive) end.