> On 16 Apr 2017, at 18:35, Karl Wagner <karl.sw...@springsup.com> wrote:
> 
>> 
>> On 16 Apr 2017, at 05:32, Dave Abrahams via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>> on Sat Apr 15 2017, Xiaodi Wu <swift-evolution@swift.org 
>> <mailto:swift-evolution@swift.org>> wrote:
>> 
>>> On Sat, Apr 15, 2017 at 3:12 PM, Dave Abrahams via swift-evolution <
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>>> 
>>>> on Thu Apr 13 2017, Xiaodi Wu <swift-evolution@swift.org 
>>>> <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>>> Getting this sorted out is definitely a worthwhile effort. I do have
>>>>> thoughts about this proposal:
>>>>> 
>>>>> I continue to have reservations about an identical spelling (e.g. `==`)
>>>>> giving two different answers with the same values of the same type,
>>>>> depending on the generic context. It is a very *clever* design, but it is
>>>>> also a very *subtle* behavior that I can see leading to much confusion
>>>> and
>>>>> befuddlement for any user who is not well versed *both* in the
>>>> intricacies
>>>>> of IEEE floating point *and* in the intricacies of Swift.
>>>> 
>>>> I can't help but think that the concern over confusion here is not
>>>> informed by any realistic situations.  Please describe
>>>> 
>>> 
>>> To be clear, I'm not claiming that my concerns about the proposal outweigh
>>> my enthusiasm for it.
>>> 
>>> But here, the confusion I'm concerned about stems from the essential
>>> conclusion by the proposal authors that types (including, but not
>>> necessarily only limited to FP types) which are ordinarily compared in a
>>> way that treats certain "special values" differently must also present an
>>> alternative notion of comparison that accounts for all possible
>>> values. 
>> 
>> That may be a conclusion, but it's not an assumption.  For example, it's
>> totally reasonable that there is a value of Int (i.e. 0) for which the
>> requirements of division don't hold.  We say that 0 is outside the
>> domain of / when used as a divisor, and we tried to get away with saying
>> that NaN was outside the domain of ==.  However, it's also reasonable to
>> trap on integer division by zero.
>> 
>> What we have is a situation where values that “misbehave” when given
>> IEEE semantics occur in normal code and are expected to interoperate
>> with other floating point values under normal circumstances (such as
>> when sorting), and not only interoperate but give reasonable results.
>> 
>> Now, having thought about this a bit more myself, here is a real case
>> where confusion might occur:
>> 
>>  if values.contains(.NaN) {
>>    print(values.filter { $0 != .NaN }) // Surprise, NaN is printed!
>>  }
>> 
>> I find this result truly loathsome, but it seems to me that the only
>> reasonable cure is giving == equivalence relation semantics under all
>> circumstances.
> 
> 
> The thing that’s bad about it is that we silently pick different operators 
> for different contexts. With Swift’s heavy use of abstraction layering, you 
> often can’t really tell what the context is (if it even has meaning at all).
> 
> I’ve been thinking about Swift architectural patterns, and one pattern that I 
> think of as being a good fit for the language is this idea of wrapping 
> operations on protocol-types as generic structs (for example, the way we do 
> FilterCollection, LazyMapCollection, and he various String views in the 
> standard library), providing transformed “views” of the object with a common 
> base protocol (which will hopefully get optimised away). I wonder if we 
> couldn’t apply a similar idea here…
> 
> So basically, every FloatingPoint will expose another pseudo-FloatingPoint 
> type which differs from its base object only in its interpretation of 
> “Comparable” operators. The type-system would enforce that you are comparing 
> them consistently.
> 
> protocol FloatingPoint: Comparable {
> 
>     /// A FloatingPoint with comparison quirks
>     ///
>     associatedtype StandardComparable: FloatingPoint
>     var comparable: StandardComparable { get }
> 
>     /// A FloatingPoint which compares according to IEEE level <whatever>
>     ///
>     associatedtype IEEEComparable: FloatingPoint = Self
>     var ieeeComparable: IEEEComparable { get }
> }
> extension FloatingPoint where IEEEComparable == Self {
>     var ieeeComparable: Self { return self }
> }
> 
> struct Float: FloatingPoint {
>    /* IEEE comparison */   
>    static func compare(_: Float, to: Float) -> ComparisonResult { ... }
> 
>    /* Quirky Float where .Nan == .Nan, +0.0 == -0.0 etc... */
>    struct StandardComparable: FloatingPoint {
>      static func compare(_: StandardComparable, to: StandardComparable) -> 
> ComparisonResult { ... }
>    }
>    var comparable: StandardComparable { return StandardComparable(self) }
> }
> 
> The idea is that the invisible context-sensitive comparison quirks would 
> become visible:
> 
> if values.contains(.NaN) { // uses IEEE rules, so is always false
>     print(values.filter { $0 != .NaN })
> }
> 
> if values.contains(where: { $0.comparable == .NaN }) { // opt-in to stdlib 
> quirks
>     print(values.filter { $0.comparable != .NaN }) // no NaNs
> }
> 
> - Karl

Oh, and:

Float.StandardComparable.IEEEComparable = Float, and
Float.StandardComparable.StandardComparable = Self

...so they wouldn’t recurse. You could just flip between views with 
“.comparable” or “.ieeeComparable”.

- Karl

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

Reply via email to