[swift-users] Subtract a set of a subclass?

Zhao Xin owenzx at gmail.com
Wed Aug 31 22:00:18 CDT 2016


I don't see the point. For example if an element in Set<B> and another
element in Set<A> are with a same hash value. Neither of the elements
should be subtracted. As they are in different types. And hash values
between different types are not guaranteed to be comparable.

import Foundation


class Foo:Hashable {

    var value: Int



    public var hashValue: Int {

        return value

    }



    public static func ==(lhs: Foo, rhs: Foo) -> Bool {

        return lhs.value == rhs.value

    }



    required init(_ value:Int) {

        self.value = value

    }

}


class Bar:Foo {

    override public var hashValue: Int {

        return value * 10

    }

}


let foo = Foo(10)

let bar = Bar(10)


print(foo.hashValue) // 10

print(bar.hashValue) // 100

print((bar as Foo).hashValue) // 100 instead of 10


print(foo == bar) // true

print(foo.hashValue == bar.hashValue) // false

As you can see in the above code, although `foo == bar` is true,
`foo.hashValue == bar.hashValue` is not guaranteed to be true. As far as I
know, Set<T> uses hash values instead of equations to compare the elements.
So the results of a super class and its sub class are not guaranteed. Also,
as `(bar as Foo).hashValue` is always the result of its own class, you
can't get the results you want through casting.

var fooSet:Set<Foo> = [Foo(10), Foo(9), Foo(8), Foo(7)]

var barSet:Set<Bar> = [Bar(8), Bar(7), Bar(6), Bar(5)]


fooSet.subtract(barSet)

fooSet.forEach { print("\(type(of:$0)), value:\($0.value)") }

/*

 Foo, value:10

 Foo, value:9

 Foo, value:8 // Here is a mystery, Foo(7) is unreasonably missing.

*/

However, if you can guarantee the hash values are comparable, you still can
get the results you want.

class Foo:Hashable {

    var value: Int



    public var hashValue: Int {

        return value

    }



    public static func ==(lhs: Foo, rhs: Foo) -> Bool {

        return lhs.value == rhs.value

    }



    required init(_ value:Int) {

        self.value = value

    }

}


class Bar:Foo {

    var name = "bar"

}


var fooSet:Set<Foo> = [Foo(10), Foo(9), Foo(8), Foo(7)]

var barSet:Set<Bar> = [Bar(8), Bar(7), Bar(6), Bar(5)]


fooSet.subtract(barSet)

fooSet.forEach { print("\(type(of:$0)), value:\($0.value)") }

/*

 Foo, value:10

 Foo, value:9

*/


Zhaoxin

On Thu, Sep 1, 2016 at 8:31 AM, Nick Brook via swift-users <
swift-users at swift.org> wrote:

> I have a set, Set<A> and a subset of that, Set<B>, where B: A. I want to
> subtract Set<B> from Set<A>, but the subtract function signature specifies
> that the set elements must be the same type (S.Generator.Element ==
> Element). I guess this is because Element is not required to be a class,
> simply hashable, therefore inheritance is not guaranteed? Is there any way
> this could be implemented in Set, in an extension, or what would be the
> most efficient way to perform that operation?
>
> Thanks
>
> Nick
>
> _______________________________________________
> 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/20160901/09d8dc8d/attachment.html>


More information about the swift-users mailing list