[swift-evolution] Proposals: (1) Forbidding custom `==` for value types, (2) `dispatch` keyword, (3) `default`-result for methods with `Self`, and (4) Poor-Mans-Existentials
Johannes Neubauer
neubauer at kingsware.de
Mon Jul 18 05:08:07 CDT 2016
Dear Félix,
As a small follow-up, because you asked what I am protecting you from. Dictionaries and Sets, for instance, will work only, if equality and hash value are computed contract conform. As soon as you let (unintendedly) differing values collapse or same values break up, you will have unintended behavior. This is crucial and I think every developer should be thankful for any help he gets here from a language. If (in the future) the swift runtime will create value pools for you, and you have a wrong implementation of equality, the complete system will just misbehave. **That** will be bugs hard to find.
All the best
Johannes
> Am 18.07.2016 um 11:50 schrieb Johannes Neubauer via swift-evolution <swift-evolution at swift.org>:
>
>
>> Am 18.07.2016 um 03:51 schrieb Félix Cloutier <felixcca at yahoo.ca>:
>>
>> Your initial rationale no longer makes sense with your suggested solution. If the dumb comparison returns false, people can still introduce side effects in the comparison method, except that now it's even harder to find out because all of my equality tests have been rewritten as "memcmp(a, b) || ==(a, b)“.
>
> No its `memcmp(a, b) && ==(a,b)`, since if the „standard equality“ says `true` there is no short-circuit, but the custom implementation has to be `true` either! It is just a pre-condition.
>
>> What are you trying to protect me from?
>
> 1. You cannot say something is unequal although the system says it is equal
> 2. You do not have to implement equality for value types, only if you really need custom behavior (so you do not write boiler-plate code, which is error prone), so side effects will be less common
> 3. With unique indirect storage (and copy-on-write) you would be able use `==` for large values, because these values are only shared for reads not for writes (future, not yet available in swift), so no race conditions
> 4. With `dispatch` in operator-methods (or any other) as well as a `default` clause for reference types, so that equality of mixed-types just result in `false`, so that this is not possible anymore (see excerpt of discussion):
>
>> Am 16.07.2016 um 15:18 schrieb Johannes Neubauer via swift-evolution <swift-evolution at swift.org>:
>>
>> This is not true for reference types. Consider the following **bad** (but compiling code):
>>
>> ```swift
>> class A: Equatable {}
>>
>> class Aa: A {
>> let a: Int
>>
>> init(a: Int) {
>> self.a = a
>> }
>> }
>>
>> func ==(lhs: A, rhs: A) -> Bool {
>> return lhs === rhs
>> }
>>
>> func ==(lhs: Aa, rhs: Aa) -> Bool {
>> return lhs.a == rhs.a
>> }
>> ```
>>
>> Now let us use this:
>>
>> ```swift
>> let a = A()
>> let a2 = A()
>> let aa = Aa(a: 0)
>> let aa2 = Aa(a: 1)
>> let aa3 = Aa(a: 1)
>>
>> // prints `true`
>> print(a == a)
>>
>> // prints `false`
>> print(a == a2)
>>
>> // prints `false`
>> print(a == aa)
>>
>> // prints `false`
>> print(a == aa3)
>>
>> // prints `false`
>> print(aa == aa2)
>>
>> // prints `true` because it compares the `a: Int` values.
>> print(aa2 == aa3)
>>
>> // now mixed-type comparison (returns `false`)
>> print(a == aa2)
>> ```
>>
>> Hence, you can do mixed-type equality checks in Swift. Even worse is, you can do this:
>>
>> ```swift
>> let aa2AsA: A = aa2,
>> aa3AsA: A = aa3
>>
>> // prints `true` because it compares the `a: Int` values.
>> print(aa2 == aa3)
>>
>> // prints `false`, because the equals method of `A` is used
>> print(aa2AsA == aa3AsA)
>> ```
>>
>> Just by assigning an object to a variable that is typed differently the result is completely different. This is because method parameters are dispatched statically. This is fast, but results in really unintended results, you can do a **lot** of things breaking the contract of `==` with that. This is why I wanted to add a `default` clause (in *3.* of my original proposal) for such methods involving two references to `Self`. Further on, I wanted to add the keyword `dispatch` for method (and operator) parameters, where dispatching is necessary (see *2.* of my original proposal).
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
More information about the swift-evolution
mailing list