[swift-users] Can we `override var hashValue`?

Zhao Xin owenzx at gmail.com
Fri Sep 2 20:42:31 CDT 2016


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> 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>
> wrote:
>
>> On Sat, Sep 3, 2016 at 1:31 AM, Zhao Xin via swift-users
>> <swift-users at swift.org> wrote:
>> > func ==(lhs: Apple, rhs: Apple) -> Bool {
>> >     return lhs.name == rhs.name && lhs.shape == rhs.shape
>> > }
>> >
>> > func ==(lhs: Banana, rhs: Banana) -> Bool {
>> >     return lhs.name == 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>*/
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160903/f6d581dc/attachment.html>


More information about the swift-users mailing list