Precedencegroup's assignment

when it set true or false, what is the difference of precedence? write a demo to descripte it

infix operator +-: AdditionPrecedence
precedencegroup myPrecedence {
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment:false // I don't find the difference of true and false
    associativity: left
}

struct Vector2D {
    var x = 0.0, y = 0.0
}

extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}

let firstVector:Vector2D? = Vector2D(x: 1, y: 2)
let secondVector =  Vector2D(x: 3, y: 4)
let plusMinus = firstVector! +- secondVector // the assignment doesn't affect the ! likely

The meaning and effect of “assignment” in precedence groups was explained in the core team’s decision notes when they returned the first version of SE-0077 “Improved operator declarations” for revision:

This proposal quietly drops the assignment modifier that exists on operators today. This modifier had one important function–an operator marked assignment gets folded into an optional chain, allowing foo?.bar += 2 to work as foo?(.bar += 2) instead of failing to type-check as (foo?.bar) += 2. In practice, all Swift operators currently marked assignment are at the equivalent of the Assignment precedence level, so the core team recommends making this optional chaining interaction a special feature of the Assignment precedence group.

I changed the demo above to below, it doesn't work

infix operator +-=: AdditionPrecedence
precedencegroup myPrecedence {
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment:true
    associativity: left
}

struct Vector2D {
    var x:Double = 0.0, y:Double = 0.0
}

extension Double {
    static func +-= (left: inout Double, right: Double) {
        left = left + right / 2
    }
}

var firstVector:Vector2D? = Vector2D(x: 1, y: 2)
let secondVector =  Vector2D(x: 3, y: 4)
firstVector?y +-= 3 // Error: '?' must be followed by a call, member lookup, or subscript

Is that supposed to be .y at the end of your chain? Because the error is just pointing out that it isn’t.

1 Like

oh, It was a stupid mistake……
It should be like below:

infix operator +-=: AdditionPrecedence
precedencegroup myPrecedence {
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment:true
    associativity: left
}

struct Vector2D {
    var x:Double = 0.0, y:Double = 0.0
}

extension Double {
    static func +-= (left: inout Double, right: Double) {
        left = left + right / 2
    }
}

var firstVector:Vector2D? = Vector2D(x: 1, y: 2)
let secondVector =  Vector2D(x: 3, y: 4)
firstVector?.y +-= 3 // It should be like @Nevin says that  ` foo?(.bar += 2) `, but it doesn't

? is not a binary operator; it doesn't interact with precedence that way. ? is a postfix unary operator (except when forming part of the ternary ? : operator), and unary operators always parse inside of binary operators.

You gave your custom operator AdditionPrecedence, which has assignment: false.

1 Like

the right answer is that as below:

infix operator +-=: myPrecedence
precedencegroup myPrecedence {
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment:true
    associativity: left
}

struct Vector2D {
    var x:Double = 0.0, y:Double = 0.0
}

extension Double {
    static func +-= (left: inout Double, right: Double) {
        left = left + right / 2
    }
}

var firstVector:Vector2D? = Vector2D(x: 1, y: 2)
let secondVector =  Vector2D(x: 3, y: 4)
firstVector?.y +-= 3

or like that

infix operator +-=: myPrecedence
precedencegroup myPrecedence {
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment:true
    associativity: left
}

struct Vector2D {
    var x:Double = 0.0, y:Double = 0.0
}

extension Vector2D {
    static func +-= (left: inout Vector2D, right: Vector2D) {
        left = Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}

var firstVector:Vector2D? = nil
let secondVector =  Vector2D(x: 3, y: 4)
firstVector? +-= secondVector // I can't believe it works,amazing

1 Like