1

This is just a language curiosity rather than problem.

The ElementAt() method of IEnumerable accepts integers to get the Nth element of an enumerable collection.

For example

var list = new List<char>() { 'a', 'b', 'c' };
var alias = list.AsEnumerable();
int N = 0;
alias.ElementAt(N); //gets 'a'

All good, however, why doesn't ElementAt() accept unsigned integers (uint) ? e.g.

uint N = 0;
alias.ElementAt(N); //doesn't compile 

I can understand why ElementAt could accept integers to allow negative indices (e.g. Python allows negative indices where list[-1] refers to the last element), so it makes sense to have accept negative indices for those languages that do use them even if C# doesn't.

But I can't quite see the reasoning for disallowing unsigned integers, if anything an unsigned integer is better as it guarantees that the index will not be negative (so only the upper bound of the range needs to be checked).

The best thing I could think of is perhaps the CLR team decided to standardize on signed integers to allow other languages (e.g. Python) that do have negative indices to use the same code and ensure the ranges would consistent across languages.

Does anyone have a better/authoritative explanation for why .ElementAt() doesn't allow unsigned ints ?

-Marcin

Marcin
  • 45
  • 6
  • 3
    Unsigned integers are not [CLS compliant](http://msdn.microsoft.com/en-us/library/12a7a7h3%28v=vs.110%29.aspx). – Hans Passant Sep 29 '14 at 04:05
  • Thanks. Opened my eyes to CLS compliance. http://stackoverflow.com/questions/6325/why-are-unsigned-ints-not-cls-compliant may be useful as well to anyone else wondering about all of this. – Marcin Sep 29 '14 at 04:17

1 Answers1

1

The real reason is that .NET arrays can be non-zero based, even if C# language does not support declaring such arrays. You can still create them using Array.CreateInstance Method (Type, Int32[], Int32[]). Note the special name of the type of the created object (System.Int32[*]) with an asterisk in it.

List is implemented using array internally, and it would not be practical to use different type for indexing.

Also, Count property usually participates in array index calculation, in which a partial result could be negative. Mixing types in an expression would be cumbersome and error prone.

Having a type which can't represent negative index would not help in error detection. Using automatical clipping with unchecked operation would not fix logical array index computation errors in an application anyway.

Following example shows negative-based array manipulation C#:

var negativeBasedArray = Array.CreateInstance(typeof(Int32),
    new []{2}, // array of array sizes for each dimension
    new []{-1}); // array of lower bounds for each dimension
Console.WriteLine(negativeBasedArray.GetType()); // System.Int32[*]
negativeBasedArray.SetValue(123, -1);
negativeBasedArray.SetValue(456, 0);
foreach(var i in negativeBasedArray)
{
    Console.WriteLine(i);
}
// 123
// 456
Console.WriteLine(negativeBasedArray.GetLowerBound(0)); // -1
Console.WriteLine(negativeBasedArray.GetUpperBound(0)); // 0
George Polevoy
  • 7,450
  • 3
  • 36
  • 61