[swift-users] Can we `override var hashValue`?
Jordan Rose
jordan_rose at apple.com
Tue Sep 6 12:39:26 CDT 2016
As I’ve said before, this doesn’t work.
let x: Fruit = Apple(“a”, shape: .medium)
let y: Fruit = Apple(“a”, shape: .big)
print(x == y) // will print true
If you want == to behave differently for subclasses, it needs to call a method that can be overridden. Static overloads will not produce the same behavior.
Jordan
> On Sep 2, 2016, at 18:42, Zhao Xin via swift-users <swift-users at swift.org> wrote:
>
> The key is how to write the `==` function. It should compare the` dynamicType`(or `type(of:)` in Swift 3.0) if the class is not a final class.
>
> func ==(lhs: Fruit, rhs: Fruit) -> Bool {
>
> print(lhs.hashValue)
> print(rhs.hashValue)
>
> return type(of:lhs) == type(of:rhs) && lhs.name == rhs.name
> }
>
> func ==(lhs: Apple, rhs: Apple) -> Bool {
> return type(of:lhs) == type(of:rhs) && lhs.name == rhs.name && lhs.shape == rhs.shape
> }
>
> func ==(lhs: Banana, rhs: Banana) -> Bool {
> return type(of:lhs) == type(of:rhs) && lhs.name == rhs.name && lhs.shape == rhs.shape
> }
>
>
> class Fruit:Hashable {
> let name:String
>
> var hashValue: Int {
> return 0
> }
>
> init(_ name:String = "common fruit") {
> self.name = name
> }
> }
>
> enum FruitShape:Int {
> case small = 1000
> case medium = 2000
> case big = 3000
> }
>
> class Apple:Fruit {
> let shape:FruitShape
>
> override var hashValue: Int {
> return 5
> }
>
> required init(_ name:String = "common fruit", shape:FruitShape = .medium) {
> self.shape = shape
> super.init(name)
> }
> }
>
> class Banana:Fruit {
> let shape:FruitShape
>
> override var hashValue: Int {
> return 10
> }
>
> required init(_ name:String = "common fruit", shape:FruitShape = .medium) {
> self.shape = shape
> super.init(name)
> }
> }
>
> let apple = Apple()
> let banana = Banana()
>
> print(apple == banana)
> /*
> 5
> 10
> false
> */
>
> I got the idea from book "Core Java", mine is version 8, the latest is the version 10. I learnt how to writing Object oriented code from it. I am glad it is still useful.
>
> Zhaoxin
>
> On Sat, Sep 3, 2016 at 9:14 AM, Zhao Xin <owenzx at gmail.com <mailto:owenzx at gmail.com>> wrote:
> There is no reason to compare the shape, it is a constant in each of
> these types. (So I am not sure what your point is.)
>
> Sorry. The `let shape` should be `var shape`. I just wanted to make the subclass to be something more than the super class.
>
> If two values are equal, their hash values should be equal. As long
> as your override implementation guarantees this, you can override
> hashValue.
>
> But the question is how? If this must be guaranteed by the subclass, how to writing the override? Or it just can't be done?
>
> You should also understand that the ==(Apple, Apple) and ==(Banana,
> Banana) are not overrides for ==(Fruit, Fruit), and they would not be
> called through dynamic dispatch when you have, for example, two apples
> typed as fruits.
>
> In fact, in my example code, `apple` and `banana` is instance of `Apple` and `Banana`. They are not using `let apple:Fruit = Apple()`. The `==` used the `Fruit` version as it was the only appropriate one. My big question is, since they used the `Fruit` version, and the `Fruit` version of `hashValue` could guarantee the `hashValue` equality, isn't that enough?
>
> Zhaoxin
>
>
> On Sat, Sep 3, 2016 at 7:02 AM, Dmitri Gribenko <gribozavr at gmail.com <mailto:gribozavr at gmail.com>> wrote:
> On Sat, Sep 3, 2016 at 1:31 AM, Zhao Xin via swift-users
> <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
> > func ==(lhs: Apple, rhs: Apple) -> Bool {
> > return lhs.name <http://lhs.name/> == rhs.name <http://rhs.name/> && lhs.shape == rhs.shape
> > }
> >
> > func ==(lhs: Banana, rhs: Banana) -> Bool {
> > return lhs.name <http://lhs.name/> == rhs.name <http://rhs.name/> && lhs.shape == rhs.shape
> > }
>
> There is no reason to compare the shape, it is a constant in each of
> these types. (So I am not sure what your point is.)
>
> > My question is, apple equals banana, but their hashValues (in their own
> > types) don't. What's wrong here? Is that means we shouldn't override
> > hashValue in subclass in Swift?
>
> This means you should not override hashValue in this particular way.
> If two values are equal, their hash values should be equal. As long
> as your override implementation guarantees this, you can override
> hashValue.
>
> You should also understand that the ==(Apple, Apple) and ==(Banana,
> Banana) are not overrides for ==(Fruit, Fruit), and they would not be
> called through dynamic dispatch when you have, for example, two apples
> typed as fruits.
>
> Dmitri
>
> --
> main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
> (j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com <mailto:gribozavr at gmail.com>>*/
>
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160906/0381be09/attachment.html>
More information about the swift-users
mailing list