Why is the collection index and count an Int instead of UInt


I've been wondering for a while now if there is any reason why

  • accessing an element in an array (Sequence) is done by an Int instead of an UInt
  • count returns an Int instead of an UInt

I haven't come to a answer myself, but I considered the following:

  • You don't want to cast between UInt and Int all the time, even though I think this won't be an issue because people would use UInts probably more often
  • Someone implementing the protocol could have a collection with negative indexes and negative count. Is there any example for this?
  • Because of objective-c interoperability
  • Because people are used to it from other languages

Advantages UInts could bring:

  • More "safety" since negative values can't be used to access elements
  • It would be more natural because people don't expect the count or index to be negative

However, I feel like I missed something. I know this will not change anyway. I just want to know if there is any "important" reason for this.

Someone had a reason for this at any point of swift development. So I felt like this is a good place to ask.

1 Like

I think that's the main reason - but I have no link for reference...
C would automatically convert numeric types, so you don't even notice when this happens; in Swift, this would be much more annoying.

1 Like

Note that Collection index doesn't have to be an Int, the only requirement is that it has to implement Comparable

In fact the only Collection that uses an Int that I can think of is an Array
Dictionary, String, Set, etc use custom structs for their indices

As for why Array uses Int - I also think that's because that would be annoying.
Either you use Collection methods like index(after:) to get and manipulate indices, in which case it doesn't matter if it's an Int or UInt, or you do arithmetic yourself, and most of number in apps are Int which means you would have to convert which is annoying and doesn't give you much more safety imo.

There’s a note regarding the preference of Int over UInt in Language Guide – The Basics

Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this isn’t the case, Int is preferred, even when the values to be stored are known to be nonnegative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference.

With that said, collection’s index is not necessarily Int like @cukr said.


A few things you might want to do with an integer index on an array:

  1. Access some value in a collection (array[someIndex])
  2. Remember the position of an item (array.index(of: someValue) )
  3. Compare two positions: (index1 < index2)
  4. Do math on two indices: (let changeInPosition = index2 - index1)

For the first case, using unsigned indexes would prevent you from literally writing array[-2], but wouldn't stop you from writing broken code like this:

let earlierIndex: UInt = otherIndex - 1 // Oops, otherIndex is 0
let value = array[earlierIndex]

If you're doing math to calculate an index, UInts won't save you from incorrect calculations; they'll just make you crash at a different point. Either way, your math needs to be correct.

So case 1 above doesn't really benefit from unsigned indexes
Cases 2 & 3 above work just as well with signed or unsigned indexes
Case 4 gets more annoying with unsigned indexes:

// This would crash if newIndex < oldIndex using UInts
let changeInPosition = newIndex - oldPosition 

Using UInts for array indexes would be unlikely to catch many real-world problems, but would result in usability issues when you want to do other useful things. So there's not really any benefit to using them.


And, in addition, an array with more than 2^63 elements is not practical on any platform supported by Swift. And a sparse array would be its own type, and could use whatever it liked for an index, such as UInt or some BigInt type.