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