Associative arithmetic operation order matters in Swift?

And subtraction is not associative whether trapping or not. :wink:

I gave the paper a quick scan but didn't quite get it, do they suggest to retry the trapping operation with widen operands or what? Sounds inefficient.

While playing with this idea I've encountered this little gotcha which does look odd:

struct Foo {}
struct Bar {}

func + (lhs: Bar, rhs: Bar) -> Foo { .init() }
func + (lhs: Bar, rhs: Foo) -> Foo { .init() }
func + (lhs: Foo, rhs: Bar) -> Foo { .init() }
func + (lhs: Foo, rhs: Foo) -> Foo { .init() }

let a = Bar()
let b = Bar()
var foo: Foo
foo = (a + b) + (a + b) // ✅
let foo2: Foo = (a + b) + (a + b) // 🛑 Cannot convert value of type 'Bar' to specified type 'Foo'
Otherwise it works, but not convenient to use.
struct IntermediateResult {
    var val: Int
    var value: Int8 {
        Int8(val) // can trap
    }
}

struct Integer8: ExpressibleByIntegerLiteral {
    let val: Int8
    init(_ val: Int8) {
        self.val = val
    }
    init(integerLiteral value: Int8) {
        self.val = value
    }
}

func + (lhs: Integer8, rhs: Integer8) -> IntermediateResult {
    let (v, overflow) = lhs.val.addingReportingOverflow(rhs.val)
    if overflow {
        return IntermediateResult(val: Int(lhs.val) + Int(rhs.val))
    } else {
        return IntermediateResult(val: Int(v))
    }
}

func + (lhs: Integer8, rhs: IntermediateResult) -> IntermediateResult {
    if let rhs = Int8(exactly: rhs.val) {
        return lhs + Integer8(rhs)
    } else {
        return IntermediateResult(val: Int(lhs.val) + rhs.val)
    }
}
func + (lhs: IntermediateResult, rhs: Integer8) -> IntermediateResult {
    if let lhs = Int8(exactly: lhs.val) {
        return Integer8(lhs) + rhs
    } else {
        return IntermediateResult(val: lhs.val + Int(rhs.val))
    }
}
func + (lhs: IntermediateResult, rhs: IntermediateResult) -> IntermediateResult {
    if let lhs = Int8(exactly: lhs.val), let rhs = Int8(exactly: rhs.val) {
        return Integer8(lhs) + Integer8(rhs)
    } else {
        return IntermediateResult(val: Int(lhs.val) + Int(rhs.val))
    }
}

var a: Integer8 = 100
var b: Integer8 = -100
var c: Integer8 = 100

var r: IntermediateResult
r = a + b + c // ok
print(r.value)
r = a + c + b // still ok
print(r.value)
r = a + c
print(r.value) // not ok