robnik
1
This doesn't seem right. Is it a bug?
Error: Protocol 'Sequence' requires that 'N.Stride' conform to 'SignedInteger'
class Foo<N: UnsignedInteger> {
let n: N
init(n: N) { self.n = n }
func bar() {
for i in 1...n { // Error here
print("i = \(n)")
}
}
}
1 Like
Nevin
2
That error message is not helpful. Probably worth filing a bug about the diagnostic alone.
After all, the operator itself works just fine. You can write let range = 1...n and it will compile.
The problem is that ranges only conform to Sequence when their bounds are strideable with a signed-integer stride.
I am not sure why it’s implemented that way. It seems like an unnecessary restriction.
hborla
(Holly Borla)
3
It's worth noting that the error message does have an attached note to this effect:
note: requirement from conditional conformance of 'ClosedRange<N>' to 'Sequence'
extension ClosedRange : Sequence where Bound : Strideable, Bound.Stride : SignedInteger {
^
I do agree though that it's not clear from the error message where the Sequence requirement came from.
2 Likes
xwu
(Xiaodi Wu)
4
To stride through a range, one needs to use advanced(by:), which takes a signed integer value. This poses no practical restriction: semantically, all strideable numeric types (whether signed or unsigned) must have a signed Stride because the type must be able to represent both positive and negative distances (since the distance from a larger positive number to a smaller positive number is negative). And indeed, all concrete unsigned integer types in the standard library have signed Stride types.
If I recall, the reason that the protocol itself, UnsignedInteger, doesn't happen to require a signed Stride is that the ability to express such a constraint in Swift was not worked out in time for this to be changed before ABI stability. So, it is just a matter of writing class Foo<N: UnsignedInteger where N.Stride: SignedInteger> { ... } here and similar boilerplate elsewhere.
3 Likes