I'm trying to add conditional Equatable
conformance to a type say Box<T>
, if T
is Equatable
. Since Swift.Void
is not Equatable
, Box<Void>
is not Equatable
.
struct Box<T> {
//...
}
extension Box: Equatable where T: Equatable {
}
I can define a new type like below as a solution:
public struct Empty: Equatable {
}
And then use Box<Empty>
instead of Box<Void>
and that would work. But, wondering if there any alternatives to introducing a new type.
Update: I tried this but it doesn't work
struct Box<T> {
//...
}
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
extension Box where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
I get an error during compilation: FooBarBaz does not conform to protocol Equatable
enum FooBarBaz: Equatable {
case success(box: Box<Void>)
// case success(box: Box<Int>) compiles as expected.
}
Please note that I'm using Swift 4.1
I get an error during compilation:
FooBarBaz
does not conform to protocolEquatable
This half-answer focuses on explaining why the approach you've tried yourself will not (yet) work.
There is a limitation, currently, with conditional conformances, that will limit you from using this particular technique to achieve your goal. Citing SE-0143: Conditional conformances, implemented in Swift 4.1:
Multiple conformances
Swift already bans programs that attempt to make the same type conform to the same protocol twice, e.g.:
...
This existing ban on multiple conformances is extended to conditional conformances, including attempts to conform to the same protocol in two different ways.
...
The section overlapping conformances describes some of the complexities introduced by multiple conformances, to justify their exclusion from this proposal. A follow-on proposal could introduce support for multiple conformances, but should likely also cover related features such as private conformances that are orthogonal to conditional conformances.
Which wont allow us to construct multiple conditional conformances as e.g.:
struct Box<T> { }
extension Box: Equatable where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
// error: redundant conformance of 'Box<T>' to protocol 'Equatable'
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
On the other hand, if we look at your own example:
struct Box<T> { }
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
extension Box where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
// error: type 'Void' does not conform to protocol 'Equatable'
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>())
Swift accurately identifies that Box<Void>
is not Equatable
: the extension Box where T == Void
will not mean that Box<Void>
conforms to Equatable
, as it does not leverage a conditional conformance of Box
to Equatable
when T
is Void
(it just provides a ==
method in case T
is Void
.
Conditional conformances express the notion that a generic type will conform to a particular protocol only when its type arguments meet certain requirements.
As a side note, the following example yields expected results:
struct Box<T> { }
extension Box: Equatable where T == () {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>()) // Box<()> is Equatable
whereas, peculiarly, replacing the conditional conformance of Box
to Equatable
if T == ()
with the typedef
of ()
, namely Void
, crashes the compiler:
struct Box<T> { }
extension Box: Equatable where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>()) // compiler crash
Assertion failed: (isActuallyCanonicalOrNull() && "Forming a CanType out of a non-canonical type!"), function CanType,
file /Users/buildnode/jenkins/workspace/oss-swift-4.1-package-osx/swift/include/swift/AST/Type.h, line 393.
...
Edit: apparently is a (now resolved) bug:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With