Refining SE-0185: Should providing a custom == suppress the default hashValue?

SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:

struct Foo: Hashable {
  // This property is "part of the value"
  var involvedInEquality: Int
  // This property isn't; maybe it's a cache or something like that
  var notInvolvedInEquality: Int

  static func ==(a: Foo, b: Foo) -> Bool {
    return a.involvedInEquality == b.involvedInEquality
  }
}

As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?

-Joe

+1. The proposal wasn’t explicit enough to have either supported or be against this IMO. It’s a sensible thing to spell out.

Daniel Duan

···

Sent from my iPhone

On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:

struct Foo: Hashable {
// This property is "part of the value"
var involvedInEquality: Int
// This property isn't; maybe it's a cache or something like that
var notInvolvedInEquality: Int

static func ==(a: Foo, b: Foo) -> Bool {
   return a.involvedInEquality == b.involvedInEquality
}
}

As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

+1. I think there is a reasonable general principle at work here: the semantics of the implementation of a refining protocol depend upon the semantics of the implementation of a refined protocol. For this reason the compiler should not synthesize an implementation for a refining protocol unless it also synthesizes (and can therefore reason about) the implementation of the refined protocol.

···

On Dec 15, 2017, at 11:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:

struct Foo: Hashable {
// This property is "part of the value"
var involvedInEquality: Int
// This property isn't; maybe it's a cache or something like that
var notInvolvedInEquality: Int

static func ==(a: Foo, b: Foo) -> Bool {
   return a.involvedInEquality == b.involvedInEquality
}
}

As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Is possible to make the compile check what is used inside of == and then
provide the hash value? And if compile cannot check (for whatever reason)
what’s properties is used inside == then raise a compile error?

···

Em sex, 15 de dez de 2017 às 15:58, Joe Groff via swift-evolution < swift-evolution@swift.org> escreveu:

SE-0185 is awesome, and brings the long-awaited ability for the compiler
to provide a default implementation of `==` and `hashValue` when you don't
provide one yourself. Doug and I were talking the other day and thought of
a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:

struct Foo: Hashable {
  // This property is "part of the value"
  var involvedInEquality: Int
  // This property isn't; maybe it's a cache or something like that
  var notInvolvedInEquality: Int

  static func ==(a: Foo, b: Foo) -> Bool {
    return a.involvedInEquality == b.involvedInEquality
  }
}

As currently implemented, the compiler will still give `Foo` the default
hashValue implementation, which will use both of `Foo`'s properties to
compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

+1, that sounds like a reasonable way to handle that situation.

This is another one of those pitfalls that could be mitigated with
something like the "transient" attribute that was discussed in earlier
discussion threads, but that's really about a slightly different problem
statement—it would let users avoid defining an explicit implementation
entirely by giving them finer control of what gets used in synthesis. But
even if we had that capability (and the time to design and implement it),
cases would still exist where someone needs to provide an explicit ==, and
the nature of those situations implies a *high probability* that the
synthesized hashValue will be inconsistent. This is a nice lower-cost way
of taking away a possible foot-gun.

···

On Fri, Dec 15, 2017 at 9:58 AM Joe Groff <jgroff@apple.com> wrote:

SE-0185 is awesome, and brings the long-awaited ability for the compiler
to provide a default implementation of `==` and `hashValue` when you don't
provide one yourself. Doug and I were talking the other day and thought of
a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:

struct Foo: Hashable {
  // This property is "part of the value"
  var involvedInEquality: Int
  // This property isn't; maybe it's a cache or something like that
  var notInvolvedInEquality: Int

  static func ==(a: Foo, b: Foo) -> Bool {
    return a.involvedInEquality == b.involvedInEquality
  }
}

As currently implemented, the compiler will still give `Foo` the default
hashValue implementation, which will use both of `Foo`'s properties to
compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?

-Joe

SE-0185 is awesome, and brings the long-awaited ability for the compiler
to provide a default implementation of `==` and `hashValue` when you don't
provide one yourself. Doug and I were talking the other day and thought of
a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:

struct Foo: Hashable {
  // This property is "part of the value"
  var involvedInEquality: Int
  // This property isn't; maybe it's a cache or something like that
  var notInvolvedInEquality: Int

  static func ==(a: Foo, b: Foo) -> Bool {
    return a.involvedInEquality == b.involvedInEquality
  }
}

As currently implemented, the compiler will still give `Foo` the default
hashValue implementation, which will use both of `Foo`'s properties to
compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?

I would agree with the other people saying automatic implementation of
Hashable should be all-or-nothing, but this makes me wonder : shouldn't
this "all-or-nothign" rule be the same for all the automatically
implemented protocol ? If no, then how would you know, just by looking at
the protocol, which function is "overridable" and which isn't ? I suppose
trying and having the compiler raise an error shouldn't be the only option.

···

On Fri, Dec 15, 2017 at 6:58 PM, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That kind of analysis would be brittle and error-prone. As Tony noted, it might be interesting at some point to have a more declarative means of describing what properties get used to synthesize structural operations on a type, which might allow you to override the default behavior in one place and still get consistent synthesized operations in terms of a different set of properties. That would be a whole new feature, though, that would take longer to discuss and design.

-Joe

···

On Dec 15, 2017, at 10:08 AM, Wallacy <wallacyf@gmail.com> wrote:

Is possible to make the compile check what is used inside of == and then provide the hash value? And if compile cannot check (for whatever reason) what’s properties is used inside == then raise a compile error?

+1
I think the simple solution of if you provide either == or hashValue you have to provide both is the best approach. Good catch of this bug.
-- Howard.

···

On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution <swift-evolution@swift.org> wrote:

+1. The proposal wasn’t explicit enough to have either supported or be against this IMO. It’s a sensible thing to spell out.

Daniel Duan
Sent from my iPhone

On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:

struct Foo: Hashable {
// This property is "part of the value"
var involvedInEquality: Int
// This property isn't; maybe it's a cache or something like that
var notInvolvedInEquality: Int

static func ==(a: Foo, b: Foo) -> Bool {
  return a.involvedInEquality == b.involvedInEquality
}
}

As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That would certainly be a simple rule. However, I think that it's more likely that someone might write their own hashValue in a way that's compatible with the default-derived equality semantics, so providing only explicit hashValue feels less problematic to me than providing explicit == and forgetting hashValue.

-Joe

···

On Dec 15, 2017, at 11:39 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

+1
I think the simple solution of if you provide either == or hashValue you have to provide both is the best approach. Good catch of this bug.

Can we provide a 'standard' method/function that can be used to combine
ordered hash values (`[Int] -> Int`)? That could make manually implementing
`hashValue` less burdensome.

TJ

···

On Fri, Dec 15, 2017 at 12:08 PM, Tony Allevato via swift-evolution < swift-evolution@swift.org> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

+1
I think the simple solution of if you provide either == or hashValue you
have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are
times where a value is composed of N fields where N is large-ish, and
equality is dependent on the values of all N fields but the hash value only
needs to be "good enough" by considering some subset of those fields (to
make computing it more efficient).

That still satisfies the related relationship between == and hashValue,
but a user wanting to explicitly implement a more efficient hashValue
should *not* necessarily be required to explicitly write the same == that
would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution < >> swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be
against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution < >> swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the
compiler to provide a default implementation of `==` and `hashValue` when
you don't provide one yourself. Doug and I were talking the other day and
thought of a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the
default hashValue implementation, which will use both of `Foo`'s properties
to compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

@regexident has a long-standing proposal about how to do hashing better that would address this:

Dave

···

On Dec 15, 2017, at 2:04 PM, T.J. Usiyan via swift-evolution <swift-evolution@swift.org> wrote:

Can we provide a 'standard' method/function that can be used to combine ordered hash values (`[Int] -> Int`)? That could make manually implementing `hashValue` less burdensome.

TJ

On Fri, Dec 15, 2017 at 12:08 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
+1
I think the simple solution of if you provide either == or hashValue you have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are times where a value is composed of N fields where N is large-ish, and equality is dependent on the values of all N fields but the hash value only needs to be "good enough" by considering some subset of those fields (to make computing it more efficient).

That still satisfies the related relationship between == and hashValue, but a user wanting to explicitly implement a more efficient hashValue should *not* necessarily be required to explicitly write the same == that would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

+1
I think the simple solution of if you provide either == or hashValue you
have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are
times where a value is composed of N fields where N is large-ish, and
equality is dependent on the values of all N fields but the hash value only
needs to be "good enough" by considering some subset of those fields (to
make computing it more efficient).

That still satisfies the related relationship between == and hashValue, but
a user wanting to explicitly implement a more efficient hashValue should
*not* necessarily be required to explicitly write the same == that would be
synthesized for them in that case.

···

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution < swift-evolution@swift.org> wrote:

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution < > swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be
against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the
compiler to provide a default implementation of `==` and `hashValue` when
you don't provide one yourself. Doug and I were talking the other day and
thought of a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the
default hashValue implementation, which will use both of `Foo`'s properties
to compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think that is an advanced use, rather than a common use. I would prefer that to be something you manually code.

-- Howard.

···

On 16 Dec 2017, at 7:08 am, Tony Allevato <tony.allevato@gmail.com> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:
+1
I think the simple solution of if you provide either == or hashValue you have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are times where a value is composed of N fields where N is large-ish, and equality is dependent on the values of all N fields but the hash value only needs to be "good enough" by considering some subset of those fields (to make computing it more efficient).

That still satisfies the related relationship between == and hashValue, but a user wanting to explicitly implement a more efficient hashValue should *not* necessarily be required to explicitly write the same == that would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution <swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

In Java they have simple to use var arg library functions that equate and hash values. I have written similar in my own code. Something like:

    func equate<T0, T1>(_ e0: (T0, T0), _ e1: (T1, T1)) -> Bool where T0: Equatable, T1: Equatable {
        return e0.0 == e0.1 && e1.0 == e1.1
    }

Unfortunately in Swift I don’t think a var arg version is possible and the library would have to have versions up to some arity, say 7.

But it would mitigate the pain of manually writing hash and equate for the cases when the compiler written version isn’t available.

-- Howard.

···

On 16 Dec 2017, at 8:11 am, Dave DeLong via swift-evolution <swift-evolution@swift.org> wrote:

@regexident has a long-standing proposal about how to do hashing better that would address this:

https://gist.github.com/regexident/1b8e84974da2243e5199e760508d2d25

Dave

On Dec 15, 2017, at 2:04 PM, T.J. Usiyan via swift-evolution <swift-evolution@swift.org> wrote:

Can we provide a 'standard' method/function that can be used to combine ordered hash values (`[Int] -> Int`)? That could make manually implementing `hashValue` less burdensome.

TJ

On Fri, Dec 15, 2017 at 12:08 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:
+1
I think the simple solution of if you provide either == or hashValue you have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are times where a value is composed of N fields where N is large-ish, and equality is dependent on the values of all N fields but the hash value only needs to be "good enough" by considering some subset of those fields (to make computing it more efficient).

That still satisfies the related relationship between == and hashValue, but a user wanting to explicitly implement a more efficient hashValue should *not* necessarily be required to explicitly write the same == that would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution <swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think that is an advanced use, rather than a common use. I would prefer
that to be something you manually code.

But why? Why should implementing a subset of fields for hashValue require a
developer to also manually implement == when the default synthesized
version would be perfectly fine? The relationship between Equatable and
Hashable does not go both ways.

In fact, requiring that they do so is *more* error prone because now
they're being forced to implement something that the compiler would have
otherwise generated for them.

···

On Fri, Dec 15, 2017 at 6:41 PM Howard Lovatt <howard.lovatt@gmail.com> wrote:

-- Howard.

On 16 Dec 2017, at 7:08 am, Tony Allevato <tony.allevato@gmail.com> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

+1
I think the simple solution of if you provide either == or hashValue you
have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are
times where a value is composed of N fields where N is large-ish, and
equality is dependent on the values of all N fields but the hash value only
needs to be "good enough" by considering some subset of those fields (to
make computing it more efficient).

That still satisfies the related relationship between == and hashValue,
but a user wanting to explicitly implement a more efficient hashValue
should *not* necessarily be required to explicitly write the same == that
would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution < >> swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be
against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution < >> swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the
compiler to provide a default implementation of `==` and `hashValue` when
you don't provide one yourself. Doug and I were talking the other day and
thought of a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the
default hashValue implementation, which will use both of `Foo`'s properties
to compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I would say it is an advanced use because it is an optimisation and in addition an optimisation that requires a lot of knowledge of the fields to be certain that a reduced hash is going to be good enough.

The optimisation doesn’t have a great history, for example in Java they used to hash only the 1st 6 characters of a string. However this was exploited in denial of service attacks that generated a vast number of strings with the same hash value, i.e same 1st 6 characters, that then overwhelmed the dictionary (map in Java) used in the web server software to store logins.

So it wouldn’t be something I would encourage people to do or even worse do by accident.

-- Howard.

···

On 16 Dec 2017, at 3:36 pm, Tony Allevato <tony.allevato@gmail.com> wrote:

On Fri, Dec 15, 2017 at 6:41 PM Howard Lovatt <howard.lovatt@gmail.com> wrote:
I think that is an advanced use, rather than a common use. I would prefer that to be something you manually code.

But why? Why should implementing a subset of fields for hashValue require a developer to also manually implement == when the default synthesized version would be perfectly fine? The relationship between Equatable and Hashable does not go both ways.

In fact, requiring that they do so is *more* error prone because now they're being forced to implement something that the compiler would have otherwise generated for them.

-- Howard.

On 16 Dec 2017, at 7:08 am, Tony Allevato <tony.allevato@gmail.com> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:
+1
I think the simple solution of if you provide either == or hashValue you have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are times where a value is composed of N fields where N is large-ish, and equality is dependent on the values of all N fields but the hash value only needs to be "good enough" by considering some subset of those fields (to make computing it more efficient).

That still satisfies the related relationship between == and hashValue, but a user wanting to explicitly implement a more efficient hashValue should *not* necessarily be required to explicitly write the same == that would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution <swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m skeptical that your use case is common enough to justify leaving open the glaring bug magnet that started this thread. Could you give an example of a common occurrence where it would be a significant improvement to explicitly write a *less precise* hash function that’s only “good enough” and still want the more precise full equality?

TBH, I think contributors here are often too quick to demand padding the walls to protect the most incompetent of engineers from themselves, but I feel like the root proposal here is a good idea.

Those are valid concerns for hashing algorithms in general, but there's no connection between that and a statement that an explicitly implemented hashValue should also require an explicitly implemented ==. Requiring that certainly doesn't make it less likely that people will run into the problem you've described if they implement their own hashValue—if they implement it poorly, it just means that the could also shoot themselves in the foot by then being forced to also implement == and possibly doing it poorly.

IMO, it’s far easier to implement hashValue poorly, so I think reminding the dev they need to think about `==` too is more helpful than not. I’m not often in favor of the padded cell, but I would even consider a proposal to emit a warning if fields read in `==` is a strict subset of fields read in `hashValue`.

···

On Dec 15, 2017, at 9:59 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

On Fri, Dec 15, 2017 at 9:53 PM Howard Lovatt <howard.lovatt@gmail.com <mailto:howard.lovatt@gmail.com>> wrote:
I would say it is an advanced use because it is an optimisation and in addition an optimisation that requires a lot of knowledge of the fields to be certain that a reduced hash is going to be good enough.

The optimisation doesn’t have a great history, for example in Java they used to hash only the 1st 6 characters of a string. However this was exploited in denial of service attacks that generated a vast number of strings with the same hash value, i.e same 1st 6 characters, that then overwhelmed the dictionary (map in Java) used in the web server software to store logins.

So it wouldn’t be something I would encourage people to do or even worse do by accident.

-- Howard.

On 16 Dec 2017, at 3:36 pm, Tony Allevato <tony.allevato@gmail.com <mailto:tony.allevato@gmail.com>> wrote:

On Fri, Dec 15, 2017 at 6:41 PM Howard Lovatt <howard.lovatt@gmail.com <mailto:howard.lovatt@gmail.com>> wrote:
I think that is an advanced use, rather than a common use. I would prefer that to be something you manually code.

But why? Why should implementing a subset of fields for hashValue require a developer to also manually implement == when the default synthesized version would be perfectly fine? The relationship between Equatable and Hashable does not go both ways.

In fact, requiring that they do so is *more* error prone because now they're being forced to implement something that the compiler would have otherwise generated for them.

-- Howard.

On 16 Dec 2017, at 7:08 am, Tony Allevato <tony.allevato@gmail.com <mailto:tony.allevato@gmail.com>> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
+1
I think the simple solution of if you provide either == or hashValue you have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are times where a value is composed of N fields where N is large-ish, and equality is dependent on the values of all N fields but the hash value only needs to be "good enough" by considering some subset of those fields (to make computing it more efficient).

That still satisfies the related relationship between == and hashValue, but a user wanting to explicitly implement a more efficient hashValue should *not* necessarily be required to explicitly write the same == that would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the compiler to provide a default implementation of `==` and `hashValue` when you don't provide one yourself. Doug and I were talking the other day and thought of a potential pitfall: what should happen if you provide a manual implementation of `==` without also manually writing your own `hashValue`? It's highly likely that the default implementation of `hashValue` will be inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the default hashValue implementation, which will use both of `Foo`'s properties to compute the hash, even though `==` only tests one. This could be potentially dangerous. Should we suppress the default hashValue derivation when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Those are valid concerns for hashing algorithms in general, but there's no
connection between that and a statement that an explicitly implemented
hashValue should also require an explicitly implemented ==. Requiring that
certainly doesn't make it less likely that people will run into the problem
you've described if they implement their own hashValue—if they implement it
poorly, it just means that the could also shoot themselves in the foot by
then being forced to also implement == and possibly doing it poorly.

···

On Fri, Dec 15, 2017 at 9:53 PM Howard Lovatt <howard.lovatt@gmail.com> wrote:

I would say it is an advanced use because it is an optimisation and in
addition an optimisation that requires a lot of knowledge of the fields to
be certain that a reduced hash is going to be good enough.

The optimisation doesn’t have a great history, for example in Java they
used to hash only the 1st 6 characters of a string. However this was
exploited in denial of service attacks that generated a vast number of
strings with the same hash value, i.e same 1st 6 characters, that then
overwhelmed the dictionary (map in Java) used in the web server software to
store logins.

So it wouldn’t be something I would encourage people to do or even worse
do by accident.

-- Howard.

On 16 Dec 2017, at 3:36 pm, Tony Allevato <tony.allevato@gmail.com> wrote:

On Fri, Dec 15, 2017 at 6:41 PM Howard Lovatt <howard.lovatt@gmail.com> > wrote:

I think that is an advanced use, rather than a common use. I would prefer
that to be something you manually code.

But why? Why should implementing a subset of fields for hashValue require
a developer to also manually implement == when the default synthesized
version would be perfectly fine? The relationship between Equatable and
Hashable does not go both ways.

In fact, requiring that they do so is *more* error prone because now
they're being forced to implement something that the compiler would have
otherwise generated for them.

-- Howard.

On 16 Dec 2017, at 7:08 am, Tony Allevato <tony.allevato@gmail.com> >> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution < >> swift-evolution@swift.org> wrote:

+1
I think the simple solution of if you provide either == or hashValue you
have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There are
times where a value is composed of N fields where N is large-ish, and
equality is dependent on the values of all N fields but the hash value only
needs to be "good enough" by considering some subset of those fields (to
make computing it more efficient).

That still satisfies the related relationship between == and hashValue,
but a user wanting to explicitly implement a more efficient hashValue
should *not* necessarily be required to explicitly write the same == that
would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution < >>> swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or be
against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution < >>> swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the
compiler to provide a default implementation of `==` and `hashValue` when
you don't provide one yourself. Doug and I were talking the other day and
thought of a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the
default hashValue implementation, which will use both of `Foo`'s properties
to compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m skeptical that your use case is common enough to justify leaving open
the glaring bug magnet that started this thread.

The use case you're replying to is not the bug described in the original
post.

The original post described "what happens if you implement ==, but keep
synthesized hashValue?" That has a high probability of being wrong,
especially if == touches a subset of the fields but hashValue continues to
use all of them. As I stated in my original reply, I fully support plugging
that hole.

The use case I mentioned later in response to Howard is "what happens is
you implement hashValue, but keep synthesized ==?" That's perfectly valid.
The required relationship between Equatable and Hashable is that any two
values that are equal must hash to the same value, but two values that have
the same hash value need not be equal.

Could you give an example of a common occurrence where it would be a
significant improvement to explicitly write a *less precise* hash function
that’s only “good enough” and still want the more precise full equality?

Though I did mention subsets of fields earlier, that's not the only valid
case—it could just be a *different* hash function. If someone wants to
implement a different hash algorithm than the default, that should *not*
require them to also write out all the boilerplate to test the pairwise
fields for ==.

TBH, I think contributors here are often too quick to demand padding the
walls to protect the most incompetent of engineers from themselves, but I
feel like the root proposal here is a good idea.

I agree, that's why I support it :slight_smile:

···

On Fri, Dec 15, 2017 at 10:27 PM Kevin Nattinger <swift@nattinger.net> wrote:

On Dec 15, 2017, at 9:59 PM, Tony Allevato via swift-evolution < > swift-evolution@swift.org> wrote:

Those are valid concerns for hashing algorithms in general, but there's no
connection between that and a statement that an explicitly implemented
hashValue should also require an explicitly implemented ==. Requiring that
certainly doesn't make it less likely that people will run into the problem
you've described if they implement their own hashValue—if they implement it
poorly, it just means that the could also shoot themselves in the foot by
then being forced to also implement == and possibly doing it poorly.

IMO, it’s far easier to implement hashValue poorly, so I think reminding
the dev they need to think about `==` too is more helpful than not. I’m not
often in favor of the padded cell, but I would even consider a proposal to
emit a warning if fields read in `==` is a strict subset of fields read in
`hashValue`.

On Fri, Dec 15, 2017 at 9:53 PM Howard Lovatt <howard.lovatt@gmail.com> > wrote:

I would say it is an advanced use because it is an optimisation and in
addition an optimisation that requires a lot of knowledge of the fields to
be certain that a reduced hash is going to be good enough.

The optimisation doesn’t have a great history, for example in Java they
used to hash only the 1st 6 characters of a string. However this was
exploited in denial of service attacks that generated a vast number of
strings with the same hash value, i.e same 1st 6 characters, that then
overwhelmed the dictionary (map in Java) used in the web server software to
store logins.

So it wouldn’t be something I would encourage people to do or even worse
do by accident.

-- Howard.

On 16 Dec 2017, at 3:36 pm, Tony Allevato <tony.allevato@gmail.com> >> wrote:

On Fri, Dec 15, 2017 at 6:41 PM Howard Lovatt <howard.lovatt@gmail.com> >> wrote:

I think that is an advanced use, rather than a common use. I would
prefer that to be something you manually code.

But why? Why should implementing a subset of fields for hashValue require
a developer to also manually implement == when the default synthesized
version would be perfectly fine? The relationship between Equatable and
Hashable does not go both ways.

In fact, requiring that they do so is *more* error prone because now
they're being forced to implement something that the compiler would have
otherwise generated for them.

-- Howard.

On 16 Dec 2017, at 7:08 am, Tony Allevato <tony.allevato@gmail.com> >>> wrote:

On Fri, Dec 15, 2017 at 11:39 AM Howard Lovatt via swift-evolution < >>> swift-evolution@swift.org> wrote:

+1
I think the simple solution of if you provide either == or hashValue
you have to provide both is the best approach. Good catch of this bug.
-- Howard.

That would be a significant usability hit to a common use case. There
are times where a value is composed of N fields where N is large-ish, and
equality is dependent on the values of all N fields but the hash value only
needs to be "good enough" by considering some subset of those fields (to
make computing it more efficient).

That still satisfies the related relationship between == and hashValue,
but a user wanting to explicitly implement a more efficient hashValue
should *not* necessarily be required to explicitly write the same == that
would be synthesized for them in that case.

> On 16 Dec 2017, at 6:24 am, Daniel Duan via swift-evolution < >>>> swift-evolution@swift.org> wrote:
>
> +1. The proposal wasn’t explicit enough to have either supported or
be against this IMO. It’s a sensible thing to spell out.
>
> Daniel Duan
> Sent from my iPhone
>
>> On Dec 15, 2017, at 9:58 AM, Joe Groff via swift-evolution < >>>> swift-evolution@swift.org> wrote:
>>
>> SE-0185 is awesome, and brings the long-awaited ability for the
compiler to provide a default implementation of `==` and `hashValue` when
you don't provide one yourself. Doug and I were talking the other day and
thought of a potential pitfall: what should happen if you provide a manual
implementation of `==` without also manually writing your own `hashValue`?
It's highly likely that the default implementation of `hashValue` will be
inconsistent with `==` and therefore invalid in a situation like this:
>>
>> struct Foo: Hashable {
>> // This property is "part of the value"
>> var involvedInEquality: Int
>> // This property isn't; maybe it's a cache or something like that
>> var notInvolvedInEquality: Int
>>
>> static func ==(a: Foo, b: Foo) -> Bool {
>> return a.involvedInEquality == b.involvedInEquality
>> }
>> }
>>
>> As currently implemented, the compiler will still give `Foo` the
default hashValue implementation, which will use both of `Foo`'s properties
to compute the hash, even though `==` only tests one. This could be
potentially dangerous. Should we suppress the default hashValue derivation
when an explicit == implementation is provided?
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution