Operator precedence in Swift

The SKActions to move all take a duration argument. To ensure that the rate of the move remains the same even if the distance is different, the duration must be computed:

SKAction.moveBy(myVector, duration: NSTimeInterval(sqrt(myVector.dx*myVector.dx + myVector.dy*myVector.dy)/1_000))

That's an awful lot of code to write for such a simple operation! To alleviate this, I extended CGVector to include a 'magnitude' variable:

extension CGVector {
    static func from(start: CGPoint, to end: CGPoint) -> CGVector {
        return CGVector(dx: end.x-start.x, dy: end.y-start.y)
    }
    var magnitude: CGFloat {
        return sqrt(dx^2 + dy^2)
    }
}

The constant-rate move action could then be created much more simply:

SKAction.moveBy(myVector, duration: NSTimeInterval(myVector.magnitude/1_000))

All seemed to be going well, but I soon noticed a bug in the magnitude:

CGVector(dx: 0, dy: 200).magnitude //returns 200, as expected
CGVector(dx: 200, dy: 0).magnitude //returns 4000 unexpectedly

The source of this bug was actually the ^ function, which I had defined myself:

func ^ (lhs: CGFloat, rhs: CGFloat) -> CGFloat {
    return pow(lhs, rhs)
}

My assumption had been that I had extended the exponentiation operator to work with CGFloats. However, the Swift Language Reference states that ^ is actually the bitwise XOR operator and has the same precedence as the addition operator. So the expression (dx^2 + dy^2was actually parsed from left to right, resulting in the equivalent of (((dx^2) + dy)^2)! So dx was squared twice.

The solution? Rather than trying to make the bitwise XOR work as an exponentiation operator, I could just use the power function directly:

sqrt(pow(dx, 2) + pow(dy, 2))

Update: Another alternative that was suggested to me was to just use dx * dx instead of pow(dx, 2).
The result:
sqrt(dx*dx + dy*dy)

Comments

Popular posts from this blog

The Hidden Garageband Sampler (and other features)

How to add a folder to Launchpad