At WWDC 2015, Apple engineers Doug Gregor and Bill Dudney reviewed Swift’s support for value types and explained how it can be used to build better apps by providing a flexible approach to immutability.
Gregor started off reviewing the usual reference semantics that is available in Objective-C. The main issue of reference semantics lays with the possibility of unintended sharing of objects, which makes it possible to change an object’s attribute behind its back. This is well known to Objective-C programmers, since many Cocoa and Cocoa Touch classes such as NSString, NSURLRequest, and all collections require copying. To make defensive copying easier on the programmer, the Objective-C language does even provide a copy
attribute for properties, so that the runtime itself will make a copy when assigning an object to a given property.
Defensive copying is clearly suboptimal respect of performance and memory usage, and when not done right may be the cause of subtle problems.
Gregor goes on considering whether immutability may be the right answer to this problem. Immutability is enforced by many Cocoa classes, such as NSDate
, NSURL
, UIImage
, NSNumber
and many others. Immutability has, according to Gregor, many advantages, such as the absence of side effects and sharing, but it also can lead to awkard interfaces and does not map efficiently to the machine model. Specifically, Gregor reviews an implementation of the Sieve of Eratosthenes both in Haskell and Swift to show how immutability exacts a cost in terms of performance.
According to Gregor, the right answer to this kind of problems is provided by the use of value semantics, which is fully supported in Swift:
- all fundamental types such as
Int
,Double
,String
etc. are value types; - all of Swift’s collections such as
Array
,Set
, andDictionary
are value types; - value types compose, so tuples, structs, and enums that contain only value types are themselves value types, thus allowing to build abstractions with value semantics.
Value types are just values, and are immutable. They have no identity and so they are distinguished by values. This requires that all value types shall implement the Equatable
protocol:
protocol Equatable {
/// Reflexive - `x == x` is `true`
/// Symmetric - `x == y` then `y == x`
/// Transitive - `x == y` and `y == z` then `x == z`
func ==(lhs: Self, rhs: Self) -> Bool
}
Furthermore, value types allows to get the right balance of mutability and immutability that an app requires. Indeed, says Gregor, you can use the let
keyword with a value type to specify a variable that will never change, or var
to specify that it is possible to update the value without affecting any other value:
let numbers = [1, 2, 3, 4]
var strings = [String]()
for x in numbers {
strings.append(String(x))
}
As mentioned, value types are immutable, so they are copied. But, Gregor says, their copy is cheap: for simple value types such as Int
, Double
, CGPoint
, etc., copying is constant time. For extensible data structures, copy-on-write is used which will make a copy only when the value is changed, so it is more efficient than the approach of copying by default.
The second part of the talk focuses on providing a hands-on example of programming in Swift using value types.