How does UnboundedRange work?

I can't find find much information on UnboundedRange, UnboundedRange_, and the uncallable .... A text search shows that "UnboundedRange_" only appears twice in the entire Swift codebase. So how does any of them work?

It’s literally just an operator.

And Collection has a subscript which takes an input of that operator’s type.

For what it’s worth, there’s a 3rd occurrence in that same file, which your search summary fails to show.

It is a convenience for converting a collection to a slice (for collection types that support the operator). For instance, let string = "Hello"; let substring = string[...].

The documentation lays this out in more detail: Apple Developer Documentation

2 Likes

But at the same time, the operator isn't callable. It's implemented as a postfix operator, but it's not used as a postfix.

Right. I suppose I should've expressed myself more clearly in my question. I understand how to use it, but I don't understand how it's able to do what it does. As far as I can see, UnboundedRange_ is an empty enum, and its implementation of ... is empty and uncallable.

Correct. The type exists for the sole purpose of allowing ... to be declared, and ... is declared for the sole purpose of allowing the function itself (...) to be passed as an argument in a subscript. The type cannot be instantiated, and the operator cannot be called. It's purely a clever hack to enable a desired syntax.

8 Likes

It’s an operator that isn’t used as an operator. UnboundedRange is defined as a type alias for the type of that operator, and there’s a subscript implementation that takes that UnboundedRange. Since that funky operator is the only instance of that type, you’re passing it as a value. Kind of a hack, but it gives us that great “whole slice” syntax!

3 Likes

The problem with this hack is that it is then impossible to overload this "operator" because ... is a function, which makes it harder for other containers to support the syntax.

Ref: Add UnboundedRange support to PythonObject by liuliu · Pull Request #33 · pvieito/PythonKit · GitHub

Sorry, why does it matter that ... is a function? What would you like to do with UnboundedRange that you can't do today? Reading that PR, it's not obvious what you would do differently.

In the days of doing Swift for TensorFlow we would have something like

let ellipsis = TensorRange.ellipsis

tensor[0, ellipsis]
/// instead of tensor[0,...]

because of this.

https://github.com/tensorflow/swift/issues/188#issuecomment-489485983

Ah, so you'd normally take any RangeExpression or similar. That makes sense, thanks for explaining.