Structs and Classes in Swift

I’ve previously posted about structs and classes in Swift, let’s look a little more in depth into the subject

Differences between a struct and class

As you may know, structs use value semantics whilst classes use reference semantics. In other words if you do something like this

struct Point {
   var x: Double
   var y: Double
}

let pt1 = Point(x: 1, y: 10)
let pt2 = pt1

Your pt1.x, pt1.y values are copied to pt2.x, pt2.y. If you therefore alter p1 this does no affect p2. Swift using COW (copy on write) so this is more performant than one might think if you were making lots of copies – in other words the copying takes place only when a value is changed – so thing lazy copying of values.

Structs are stored on the stack and hence are very performant in terms of creation etc. Ofcourse if you’re making many changes to copies of a struct then things are less performant due to all the copying that needs to happen (even with COW).

Ofcourse, in a more complicated scenario, such as the Point also having a member variable which is a class, then these will be stored on the stack, but with references to the heap based classes. This is an issue for structs, if a struct contain multiple reference types it’ll incur reference counting for each reference type in the struct.

Classes on the other hand use reference semantics and therefore if we rewrite the about for a class. Then p2 is a reference to p1. Any changes to p1 will be reflected in p2

class Point {
   var x: Double
   var y: Double
}

let pt1 = Point(x: 1, y: 10)
let pt2 = pt1

Classes are stored on the heap which means that allocation will be les performant than a struct, but ofcourse if you’re passing around a reference to a class, this is more performant. However because a reference type copies the reference pointer it does ofcourse lend itself to issues around mutation of state and this becomes more of an issue when we add in concurrency.

The reference types use reference counting to handle auto-deletion (i.e. garbage collection). This does mean that a reference type will also require more space that a struct to track it’s reference counter. Also due to it using the heap, again potential concurrency issues means the OS must lock memory etc.

If you’re using String or the likes in a struct, you’re storing a reference type, hence this will incur reference counting overhead. If we’re using a String to ultimately represent known values, for example UP, DOWN, OUT_OF_SERVICE then not only will it be more type safe to use an enum, from a performance perspective this would be better, for example we can declare a status enum with a String type as a raw backing value like this

enum Status: String {
   case up = "UP"
   case down = "DOWN"
   case outOfService = "OUT_OF_SERVICE"
}