[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