By Michael Pittino

2019-01-08 13:04:53 8 Comments

C# 8.0 introduces a convenient way to slice arrays - see official C# 8.0 blogpost.

The syntax to access the last element of an array is

int value[] = { 10, 11, 12, 13 };

int a = value[^1]; // 13
int b = value[^2]; // 12

I'm wondering why the indexing for accessing the elements backwards starts at 1 instead of 0? Is there a technical reason for this?


@Martin Zikmund 2019-01-08 13:07:59

Official answer

For better visibility, here is a comment from Mads Torgersen explaining this design decision from the C# 8 blog post:

We decided to follow Python when it comes to the from-beginning and from-end arithmetic. 0 designates the first element (as always), and ^0 the “length’th” element, i.e. the one right off the end. That way you get a simple relationship, where an element's position from beginning plus its position from end equals the length. the x in ^x is what you would have subtracted from the length if you’d done the math yourself.

Why not use the minus (-) instead of the new hat (^) operator? This primarily has to do with ranges. Again in keeping with Python and most of the industry, we want our ranges to be inclusive at the beginning, exclusive at the end. What is the index you pass to say that a range should go all the way to the end? In C# the answer is simple: x..^0 goes from x to the end. In Python, there is no explicit index you can give: -0 doesn’t work, because it is equal to 0, the first element! So in Python, you have to leave the end index off completely to express a range that goes to the end: x... If the end of the range is computed, then you need to remember to have special logic in case it comes out to 0. As in x..-y, where y was computed and came out to 0. This is a common nuisance and source of bugs.

Finally, note that indices and ranges are first class types in .NET/C#. Their behavior is not tied to what they are applied to, or even to be used in an indexer. You can totally define your own indexer that takes Index and another one that takes Range – and we’re going to add such indexers to e.g. Span. But you can also have methods that take ranges, for instance.

My answer

I think this is to match the classic syntax we are used to:

value[^1] == value[value.Length - 1]

If it used 0, it would be confusing when the two syntaxes were used side-by-side. This way it has lower cognitive load.

Other languages like Python also use the same convention.

@Giacomo Alzetta 2019-01-08 17:01:43

Minor correction to Mads comment: you do not have to leave off the end index completely in python. You can use None in place of a number: [0,1,2,3,4][2:None] == [2,3,4]. But, yes you cannot use an integer as end index (without computing the length obviously).

@mowwwalker 2019-01-08 21:27:36

Wait.. what's wrong with x..? That seems fine and I've never had problem with the python [3:] syntax.

@Mariusz Pawelski 2019-01-09 00:22:00

@mowwwalker nothing wrong. I seems that x.. syntax will be supported too. It's in example of ranges proposal

@Damien_The_Unbeliever 2019-01-09 08:26:12

@mowwwalker - isn't that already covered in the quote? "So in Python ... If the end of the range is computed, then you need to remember to have special logic in case it comes out to 0"

@Giacomo Alzetta 2019-01-09 13:18:13

@mowwwalker Mads comment was about cases in which you do not know what the index value is going to be because it's computed in some way. They are saying that in the case you want to compute endIndex as a negative index (i.e. index from the end) you will have a discontinuity between negative and positive numbers because 0 isn't going to work in the correct way in that case. As I pointed out you have to replace 0 by None for that. This means your code should look like seq[startIndex:endIndex or None] for example. The or None should be omitted if endIndex is expected to be positive.

@user2357112 2019-01-09 19:14:32

It's good to see they're not repeating Python's mistake with the -0 thing. Handling that special case is a huge hassle and way too easy to forget.

@programtreasures 2019-01-10 09:20:56

How can we use with dynamic keyword? like arr[^i] where i is dynamic variable

@Joel Mueller 2019-03-07 03:01:54

@programtreasures your first mistake was using the dynamic keyword, ever.

Related Questions

Sponsored Content

20 Answered Questions

[SOLVED] How to populate/instantiate a C# array with a single value?

18 Answered Questions

[SOLVED] Array slices in C#

  • 2009-01-02 10:49:05
  • Matthew Scharley
  • 213750 View
  • 199 Score
  • 18 Answer
  • Tags:   c# arrays

10 Answered Questions

5 Answered Questions

[SOLVED] Add a new element to an array without specifying the index in Bash

  • 2009-12-23 08:59:32
  • Darryl Hein
  • 492137 View
  • 682 Score
  • 5 Answer
  • Tags:   bash arrays

25 Answered Questions

[SOLVED] Why not inherit from List<T>?

7 Answered Questions

[SOLVED] Get index of array element faster than O(n)

9 Answered Questions

[SOLVED] Why C# doesn't implement indexed properties?

11 Answered Questions

[SOLVED] What is the "right" way to iterate through an array in Ruby?

  • 2008-11-22 00:38:19
  • Tom Lehman
  • 482485 View
  • 316 Score
  • 11 Answer
  • Tags:   ruby arrays loops

2 Answered Questions

[SOLVED] Why do indexes in XPath start with 1 and not 0?

  • 2010-07-23 14:56:35
  • Edward Tanguay
  • 27101 View
  • 100 Score
  • 2 Answer
  • Tags:   xslt xpath indexing

4 Answered Questions

[SOLVED] Can array indexes be named in C#?

  • 2012-03-25 21:16:05
  • diggersworld
  • 16660 View
  • 8 Score
  • 4 Answer
  • Tags:   c# arrays indexing

Sponsored Content