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

Zhao Xin owenzx at gmail.com
Fri Sep 2 00:50:47 CDT 2016


No. I don't think what you so called principle should be applied here. For
example, I have a `class Fruit`, then I have a `class Apple:Fruit`. If they
are using different `hashValue` generating method, you suggest me to use
composition instead of inheritance?

Also, it is very common for subclass to override super class `hashValue`.
Supposing opposite, if we also have another class called `class
Banana:Fruit`, we may get the result that an `Apple` is equals to a
`Banana`, using `Fruit`,  just because they have the same `hashValue`.

If we stick to the super class `hashValue`, we may also not get the
differences between instances of a certain subclass. For example, we may
get the result that a `redApple` equals to a `greenApple`.

So in my option, if one instance equals to another instance, the foundation
should be that the `type(of:instance)` equals. If you want to enlarge the
type to their super class, you need to be careful, as they are not
guaranteed automatically.

Zhaoxin

On Fri, Sep 2, 2016 at 7:32 AM, Jordan Rose <jordan_rose at apple.com> wrote:

> The Liskov substitution principle
> <https://en.wikipedia.org/wiki/Liskov_substitution_principle> says that a
> B should always be able to be treated like an A. Your Set<A> may *already* contain
> Bs, even without them ever being statically typed as B. If you think A and
> B are unrelated types, you should be using composition rather than
> inheritance.
>
> If a subclass overrides hashValue, they must be in a position to affect ==
> as well, and it must work no matter which object is on the left-hand side.
> NSObject does this by having == call the isEqual(_:) method, but you still
> need to design your class hierarchy and isEqual(_:) methods carefully.
>
> Jordan
>
>
> On Sep 1, 2016, at 16:28, Zhao Xin <owenzx at gmail.com> wrote:
>
> I believe if B inherits A, they are not the same type. So the rule doesn't
> apply here.
>
> Zhaoxin
>
> On Fri, Sep 2, 2016 at 7:02 AM, Nick Brook <nrbrook at gmail.com> wrote:
>
>> Hi Jordan,
>>
>> Thanks for the advice.
>>
>> What if a subclass does implement hashValue differently? It seems you are
>> saying a subclass should never override hashValue? Should Set not compare
>> elements with == instead of hashValue?
>>
>> Thanks
>> Nick
>>
>> M: +44 (0)7986 048 141
>> W: http://nickbrook.me
>>
>> On 1 Sep 2016, at 23:55, Jordan Rose <jordan_rose at apple.com> wrote:
>>
>>
>> On Sep 1, 2016, at 15:44, Zhao Xin via swift-users <swift-users at swift.org>
>> wrote:
>>
>> Hi Nick,
>>
>> Glad to help.
>>
>> but when using third party classes I don’t know if the hash values are
>>> comparable
>>>
>>
>> You can create an extension with a convenient init(:), which creates a
>> new instance of  the super class basing on the instance of the sub class.
>> That will guarantee the subtraction. Below code works in Xcode 7.3.1 with
>> Swift 2.2.
>>
>> import Foundation
>>
>> func ==(lhs: Foo, rhs: Foo) -> Bool {
>>     return lhs.id == rhs.id
>> }
>>
>> class Foo:Hashable {
>>     let id:Int
>>     var hashValue: Int {
>>         return id
>>     }
>>
>>     required init(_ id:Int) {
>>         self.id = id
>>     }
>> }
>>
>> class Bar:Foo {
>>     override var hashValue: Int {
>>         return id * 5
>>     }
>> }
>>
>> 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) // error: cannot invoke 'subtract' with an
>> argument list of type '(Set<Bar>)'
>> fooSet = fooSet.subtract(barSet as Set<Foo>) // works, but not what we
>> want
>> fooSet.forEach { print("\($0.dynamicType), id:\($0.id)") }
>> /*
>>  Foo, id:7
>>  Foo, id:10
>>  Foo, id:9
>> */
>>
>>
>> This isn't really a sensible thing to do. The rules for Hashable require
>> that `a == b` implies `a.hashValue == b.hashValue`, and `a.hashValue !=
>> b.hashValue` implies `a != b`. If you break these rules you're going to
>> have problems no matter what static types you're using.
>>
>> Upcasting from Set<Bar> to Set<Foo> is the most concise way to solve this
>> problem.
>>
>> Jordan
>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160902/b745d011/attachment.html>


More information about the swift-users mailing list