I am creating a performance heavy application and was wondering which way of writing the same code runs faster in runtime.
Option 1:
let a = 1 + 2
self.doSomething(with: a)
self.doSomethingElse(with: a)
Option 2:
self.doSomething(with: 1 + 2)
self.doSomethingElse(with: 1 + 2)
If any of the options is faster, is this also true for structs? e.g.
let a = CGPoint(x: 1, y: 1)
self.doSomething(with: a)
self.doSomethingElse(with: a)
or
self.doSomething(with: CGPoint(x: 1, y: 1))
self.doSomethingElse(with: CGPoint(x: 1, y: 1))
Edit: added real world scenario
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {
return
}
let currentPoint = touch.location(in: view)
let lastPoint = touch.previousLocation(in: view)
//////////
let newPoint1 = CGPoint(x: lastPoint.x - currentPoint.x, y: lastPoint.y - currentPoint.y)
let newPoint2 = CGPoint(x: lastPoint.y - currentPoint.y, y: lastPoint.x - currentPoint.x)
// OR
let newX = lastPoint.x - currentPoint.x
let newY = lastPoint.y - currentPoint.y
let newPoint11 = CGPoint(x: newX, y: newY)
let newPoint22 = CGPoint(x: newY, y: newX)
///////
print([newPoint1, newPoint2])
print([newPoint11, newPoint22])
}
Use the let
to compute the value once. This tells the Swift compiler that the same value is being used twice and allows the Swift compiler/optimizer to generate tighter code. If you know that the value is the same, share that information with the compiler and don't make the optimizer figure that out itself (because it might not be able to).
In your example with 1 + 2
, that most assuredly generates the same code in both instances because of Constant Folding. The compiler will do the 1 + 2
at compile time, and the generated code will just pass 3
to each function call.
In your second example, the Swift compiler might not be able to recognize that you've generated two versions of the same struct
, and it could emit code that generates the struct
twice. By assigning that struct to a constant a
, Swift then knows it can pass the same struct
to the two functions and avoid creating it twice.
General rule: Giving the compiler more information allows it to make better optimizations.
Added benefit: Using let
makes your code more readable and easier to modify.
In your real world scenario:
let newPoint1 = CGPoint(x: lastPoint.x - currentPoint.x, y: lastPoint.y - currentPoint.y)
let newPoint2 = CGPoint(x: lastPoint.y - currentPoint.y, y: lastPoint.x - currentPoint.x)
// OR
let newX = lastPoint.x - currentPoint.x
let newY = lastPoint.y - currentPoint.y
let newPoint11 = CGPoint(x: newX, y: newY)
let newPoint22 = CGPoint(x: newY, y: newX)
Again the compiler will likely generate the same code because of a technique called Common Subexpression Elimination where the compiler detects and eliminates redundant expressions. But why rely on this? You know the values represent newX
and newY
, so by computing those first as constants you 1) Let the compiler know to compute this expression once, 2) Document to yourself and your readers the intent of the code.
The second example is clearer and easier to modify in addition to giving extra hints to the compiler/optimizer. Overall, it is better code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With