Playing around with Tuples and generics in Swift and wanting to understand if some experiments which I’m testing are achievable.
I created:
struct TupleAssertion<T> {
let value: T
func assertValue<each Value: Equatable>(
_ expectedValue: (repeat each Value)
) where (repeat each Value) == T {
if value == expectedValue {
print("Equal")
} else {
print("Not equaL")
}
}
}
let tupleAssertion = TupleAssertion(value: (1, 2))
tupleAssertion.assertValue((1, 2))
But unfortunately I’m getting the error:
binary operator '==' cannot be applied to two '(repeat each Value)' operands
However this approach works:
func createTuple<each Value: Equatable>(val: repeat each Value) -> (repeat each Value) {
return (repeat each val)
}
createTuple(val: 1, 2) == (1, 2)
createTuple(val: 1, 3) == (1, 2)
What changes are needed to get my first approach working?
1
It looks like you’ve added parentheses to “work around” the fact that same-element requirements (== T
) are not yet supported. Adding parentheses does not make something that isn’t supported be supported. If you write it this way, you’ll get the correct diagnostic:
) where repeat each Value == T { // Same-element requirements are not yet supported
The way you’ve written it tries to make the type repeat each Value
itself be equal to T
, which is not what you mean.
Eventually this should be supported. It’s part of the SE and it is intended to work. But it is not implemented yet.
1
You cannot use ==
on tuples of an arbitrary arity because tuples are not Equatable
. There are only comparison operators defined for tuples of up to 6 elements (SE-015).
You can iterate over the value pack (SE-0408) and compare each element yourself though. You can do this in Swift 6:
func assertValue<each Value: Equatable>(
_ expectedValue: (repeat each Value)
) where (repeat each Value) == T {
for (actual, expected) in repeat (each value, each expectedValue) {
if actual != expected {
print("Not Equal")
return
}
}
print("Equal")
}
Since the struct is called TupleAssertions
, it might make more sense to move the parameter pack to the struct:
struct TupleAssertion<each T: Equatable> {
let value: (repeat each T)
func assertValue( _ expectedValue: (repeat each T)) {
// same code as before...
}
}
Prior to Swift 6, it’s a bit more convoluted to do this. (Adapted from the code in SE-0408)
struct TupleAssertion<each T: Equatable> {
let value: (repeat each T)
private struct NotEqual: Error {}
func assertValue( _ expectedValue: (repeat each T)) {
func isEqual<U: Equatable>(_ left: U, _ right: U) throws {
if left == right {
return
}
throw NotEqual()
}
do {
repeat try isEqual(each value, each expectedValue)
} catch {
print("Not Equal!")
return
}
print("Equal")
}
}
Eventually, when SE-0283 is implemented, tuples of Equatable
elements will conform to Equatable
, and your current code will work without any changes.