People used to the offset index system instead of the String.Index. Use offset indices to name the elements, count the element is normal and natural.
This offset index system has a long history and a real meaning to the collection. The subscript s[i] has a fix meaning "getting the i-th element in this collection", which is normal and direct. Get the range with offset index, is also directly means the substring is from the i-th character up to the j-th character of the original string.
People used to play subscript, range with offset index, with countable numbers. Use string[string.index(i, offsetBy: 5)] is not as directly and easily as string[i + 5]. Also the Range<String.Index> is not as directly as Range. Developers need to transfer the Range<String.Index> result of string.range(of:) to Range to know the exact range of the substring. Range<String.Index> has a real meaning to the machine and underlying data location for the substring, but Range also has a direct location information for human beings and the abstract concept of the collection.
Offset index system is based on the nature of the collection. Each element of the collection could be located by offset, which is a direct and simple conception to any collection. Right? Even the String with String.Index has some offset index property within it. For example the count of the String, is the offset index of the endIndex.The enumerated() generated a sequence with elements contains the same offset as I provided. And when we apply Array(string), the string divided by each character and make the offset indices available for the new array.
The offset index system is just an assistant for collection, not a replacement to String.Index. We use String.Index to represent the normal underlying of the String. We also could use offset indices to represent the nature of the Collection with its elements. Providing the offset index as a second choice to access all the collection, is not only for the String struct, it is for all collections, since it is the nature of the collection concept, and developers could choose to use it or not.
We don't make the String.Index O(1), but translate the offset indices to the underlaying Collection.Index. Each time use subscript with offset index, translating them using c.index(startIndex, offsetBy:i), c.distance(from: startIndex, to:i)
We can make the offset indices available through an extension to Collection (as my GitHub repo demo: GitHub - frogcjn/OffsetIndexableCollection-String-Int-Indexable-: OffsetIndexableCollection (String Int Indexable)).
or we could make it at compile time:
for example:
c[1...]
compile to
c[c.index(startIndex, offsetBy:1)...]
let index: Int = s.index(of: "a")
compile to
let index: Int = s.distance(from: s.startIndex, to: s.index(of:"a"))
let index = 1 // if used in s only
s[index..<index+2]
compile to
let index = s.index(s.startIndex, offsetBy: 1)
s[index..<s.index(index, offsetBy: 2)]
let index = 1 // if used both in s1, s2
s1[index..<index+2]
s2[index..<index+2]
compile to
let index = 1
let index1 = s1.index(s.startIndex, offsetBy: index)
let index2 = s2.index(s.startIndex, offsetBy: index)
s1[index1..<s.index(index1, offsetBy: 2)]
s2[index2..<s.index(index2, offsetBy: 2)]
I really want the team to consider providing the offset index system as an assistant to the collection.
Thanks!
Jiannan