> Am 18.07.2016 um 13:05 schrieb L. Mihalkovic <[email protected]>:
>
> IMHO implementing your proposal would close the door on some of the things
> you do when building in-memory dbs (T == U -> TRUE for T not related to U),
> which if swift remains for small apps is not a terrible loss, but may be more
> of an issue for one day doing big-data with it.
You talk about reference types now, right? I proposed a `default` keyword,
which (in a pattern matching fashion) would catch all calls to T == U for which
no implementation exists (so this is exactly when T != U). You could of course
change for a given type hierarchy the `default` result to `true` if appropriate.
If you recall how virtual functions work. There is a V-table, which contains an
entry for each overridden function and the correct one is looked up and
executed with an implicit _self parameter for the instance on which the method
has been executed.
You could write something like this:
```swift
// you could equally write: `func ==(lhs: dispatch A, rhs: dispatch A) -> Bool
= false`
dispatch func ==(lhs: A, rhs: A) -> Bool = false {
lhs === rhs
}
// the default value `= false` is inferred...
dispatch func ==(lhs: Aa, rhs: Aa) -> Bool {
lhs.a == rhs.a
}
```
You could change the default value of course. For comparisons (`Comparable`)
you could add a closure to calculate the default value (e.g. more specialized
instances are greater than less specialized so Point3D is always greater than
Point2D, in order to get total ordering).
The implementation would create a dispatch-table for this function. The key
would be a tuple `(MetaType, MetaType)`. And the value would be the
corresponding function. If the lookup `(lhs.dynamicType, rhs.dynamicType)` does
not find a table entry (e.g. because it is `lhs.dynamicType !=
rhs.dynamicType`), then a auto-closure returning the default value (or if it is
a closure, the closure itself) is returned and executed.
Cool?
All the best
Johannes
>
> Regards
> (From mobile)
>
>> On Jul 18, 2016, at 12:21 PM, Johannes Neubauer via swift-evolution
>> <[email protected]> wrote:
>>
>> See below...
>>
>>> Am 18.07.2016 um 12:08 schrieb Johannes Neubauer via swift-evolution
>>> <[email protected]>:
>>>
>>> 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
>>>> <[email protected]>:
>>>>
>>>>
>>>>> Am 18.07.2016 um 03:51 schrieb Félix Cloutier <[email protected]>:
>>>>>
>>>>> 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.
>>
>> Sorry, wrote this in a hurry. It is `||` of course. But still the rest holds.
>>
>>>>
>>>>> 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
>>>>> <[email protected]>:
>>>>>
>>>>> 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
>>>> [email protected]
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> [email protected]
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution