Saurabh 😎
WWDC 2015: Optimizing Swift Performance
Swift heavily relies on advanced compiler optimizations to get good performance
Interesting tidbit: improving the optimizer even helps unoptimized code (i.e. during quick local development cycles) since the standard library is now optimized better, as well as Swift runtime functions
Whole Module Optimizations can perform optimizations across files
Reference Counting
One advantage of structs over classes is no need for reference counting overhead e.g. if you loop over an array of objects, then every beginning and end of loop body have to increment/decrement reference count, but avoid this overhead if looping over array of structs
However, if the struct contains a reference (i.e. a pointer to an object), then will incur reference counting overhead
Conceptually, assigning a struct is an assignment for each member variable, and the assignment of the member variable that's a reference requires insertion of retain/release
It's surprisingly common to have a struct with many reference, e.g. a User struct with String, Array, and Dictionary - and every time you assign a struct or copy it, you have to a retain/releases for each member variable
Solution: use a wrapper class, which only performs a single retain/release - however, you've now changed semantics from value to reference
See WWDC 2015 Building Better Apps with Value Types in Swift for more on this
Generics
By default, Swift emits a generic and conservative implementation of a generic function:
However, compiler also performs generic specialization
e.g. if calling min<Int>
, then Swift can specialize the generic function to just return x < y ? y : x
Previously specialization was limited to when the generic function and specialized call site were in the same file, but now much more expanded with Whole Module Optimization
Dynamic Dispatch
Swift again must be conservative when generating code for method call on object:
The compiler can only emit direct, static functions if it can guarantee that function can't be overriden
Use final
keyword to tell compiler that a member variable won't be overriden
Use private
keyword to tell compiler that a function can't be overriden
Again, also helped by Whole Module Optimization since compiler has more info and can make stronger guarantees to do early binding
This is a key reason that Swift is faster than Objective-C in OOP-heavy benchmark programs - ObjC always uses full dynamic dispatch, whereas Swift compiler can make stronger guarantees to do early binding and eliminate runtime cost