swift-evolution has had a number of discussions talking about indexing syntax - we've added the "...x" and "x..." syntax which allowed open indexing. One thing we don't have right now is a way to conveniently index from the end of the collection (e.g. to drop the last two elements from a slice).
I recently ran across this post about C# 8, it looks they are considering adding a type to represent "index from end" and giving it a unary ^ syntax (See "Index Expressions" and "Range Expressions" sections of the post).
Their example looks like this:
// indexing
var lastCharacter = myString[myString.Length-1]; // old
var lastCharacter = myString[^1]; // new
// Slicing to drop the first and last characters (adapted to our syntax):
let s = myString[1 ... ^1]
In any case, this seems like a pretty elegant way to model this - it seems that it would compose nicely onto our existing indexing, range, and half-open range design.
I like the idea of this, but how should myString[1 ... ^1] behave if the length of the string was less than 2? If it's undefined behavior then how would you write code to check that the range you're using is valid before using it?
I think the answer to both of those questions is "whatever the current behavior is". Slicing into invalid indexes produces a runtime assertion, and the type would be whatever the slice type of the collection is.
Presumably the operator would just do the appropriate calculation for you, so 1...^1 would be equivalent to 1..<endIndex - 2 or whatever, just as the C# version appears to do.
Sorry, I was just thinking about subscripting, which is where this sort of calculation would be possible. Obviously 1...^1 doesn't make sense as a standalone range as ranges exist right now, but I don't believe one would be needed for the feature as presented.
I'm not a fan of the operator ^ because it's unclear at the first sight. Defining a prefix operator that takes Int also means that the mental model for this operator will be tied to relative indices.
That approach seems like it would require some very specific compiler magic. I feel like it would be more in line with the approach Swift normally takes for this to be a regular operator that produces a range type which gets passed into a separate subscript method.
I agree that ^ is not ideal though. It seems like kind of a waste to use the character for such a small feature, and I agree with @rxwei that its meaning is not obvious. I'm not sure there's a great operator-based syntax here -- my gut feeling is that some kind of labeled subscript would work best.