[swift-evolution] Method dispatching issue with subclasses implementing Equatable protocol.
Tony Allevato
tony.allevato at gmail.com
Wed Jan 18 11:13:05 CST 2017
This seems to work for me:
```
class Super: Equatable {
let x: Int
init(x: Int) {
self.x = x
}
func equals(_ rhs: Super) -> Bool {
return x == rhs.x
}
static func ==(lhs: Super, rhs: Super) -> Bool {
return lhs.equals(rhs)
}
}
class Sub: Super {
let y: Int
init(x: Int, y: Int) {
self.y = y
super.init(x: x)
}
override func equals(_ rhs: Super) -> Bool {
if let rhs = rhs as? Sub {
return y == rhs.y && super.equals(rhs)
}
return false
}
}
let a = Sub(x: 1, y: 1)
let b = Sub(x: 1, y: 2)
let c = Sub(x: 1, y: 1)
a == b // false, expected
a == c // true, expected
a != b // true, expected
a != c // false, expected
```
Additionally, when I made the change Joe suggested, your code also worked,
so maybe there was an error when you updated it?
FWIW, the default implementation of != just invokes !(a == b) <
https://github.com/apple/swift/blob/master/stdlib/public/core/Equatable.swift#L179-L181>,
so I believe it's *impossible* (well, uh, barring busted RAM or processor I
guess) for it to return the wrong value for the same arguments if you only
implement ==.
On Wed, Jan 18, 2017 at 8:52 AM Francisco Javier Fernández Toro via
swift-evolution <swift-evolution at swift.org> wrote:
> Thank you for your answer Joe,
>
> you are right the equal(to:) wasn't a valid override, but even after
> using the one you've proposed, the behavior is not the expected one
>
>
> let a = Subclass(foo: 1, bar: 1)
> let b = Subclass(foo: 1, bar: 2)
>
> (a == b) != (a != b) // Prints true
>
> let x = SubclassWithDifferentOperator(foo: 1, bar: 1)
> let y = SubclassWithDifferentOperator(foo: 1, bar: 2)
>
> (x == y) != (x != y) // Prints false
>
> As you can see above if a subclass does not implement the global function
> !=, the equal operation seems to be broken.
>
> ---
>
> Fran Fernandez
>
> On Wed, Jan 18, 2017 at 5:44 PM, Joe Groff <jgroff at apple.com> wrote:
>
>
> > On Jan 18, 2017, at 2:59 AM, Francisco Javier Fernández Toro via
> swift-evolution <swift-evolution at swift.org> wrote:
> >
> > Hi,
> >
> > I've found that when you have a class hierarchy which implements
> Equatable, if you want to have the != operator working as expected, you
> need to override it, it's not enough with ==.
> >
> > If you don't define you own subclass != operator, Swift compiler will
> use the super class to resolve that operation.
> >
> > Is there any reason for that?
>
> The `equal(to:)` method inside `Subclass` is not a valid override of
> `Superclass` because its argument only accepts `Subclass` instances, but
> the parent method needs to work with all `Superclass` instances. If you
> write it as an override, it should work:
>
> class Subclass: Superclass {
> let bar: Int
> init(foo: Int, bar: Int) {
> self.bar = bar
> super.init(foo: foo)
> }
>
> override func equal(to: Superclass) -> Bool {
> if let toSub = to as? Subclass {
> return bar == toSub.bar && super.equal(to: to)
> }
> return false
> }
> }
>
> We should probably raise an error, or at least a warning, instead of
> silently accepting your code as an overload. Would you be able to file a
> bug on bugs.swift.org about that?
>
> -Joe
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170118/58422ca4/attachment.html>
More information about the swift-evolution
mailing list