Does swift copy on write for all structs? - swift

I know that swift will optimize to copy on write for arrays but will it do this for all structs? For example:
struct Point {
var x:Float = 0
}
var p1 = Point()
var p2 = p1 //p1 and p2 share the same data under the hood
p2.x += 1 //p2 now has its own copy of the data

Array is implemented with copy-on-write behaviour – you'll get it regardless of any compiler optimisations (although of course, optimisations can decrease the number of cases where a copy needs to happen).
At a basic level, Array is just a structure that holds a reference to a heap-allocated buffer containing the elements – therefore multiple Array instances can reference the same buffer. When you come to mutate a given array instance, the implementation will check if the buffer is uniquely referenced, and if so, mutate it directly. Otherwise, the array will perform a copy of the underlying buffer in order to preserve value semantics.
However, with your Point structure – you're not implementing copy-on-write at a language level. Of course, as #Alexander says, this doesn't stop the compiler from performing all sorts of optimisations to minimise the cost of copying whole structures about. These optimisations needn't follow the exact behaviour of copy-on-write though – the compiler is simply free to do whatever it wishes, as long as the program runs according to the language specification.
In your specific example, both p1 and p2 are global, therefore the compiler needs to make them distinct instances, as other .swift files in the same module have access to them (although this could potentially be optimised away with whole-module optimisation). However, the compiler still doesn't need to copy the instances – it can just evaluate the floating-point addition at compile-time and initialise one of the globals with 0.0, and the other with 1.0.
And if they were local variables in a function, for example:
struct Point {
var x: Float = 0
}
func foo() {
var p1 = Point()
var p2 = p1
p2.x += 1
print(p2.x)
}
foo()
The compiler doesn't even have to create two Point instances to begin with – it can just create a single floating-point local variable initialised to 1.0, and print that.
Regarding passing value types as function arguments, for large enough types and (in the case of structures) functions that utilise enough of their properties, the compiler can pass them by reference rather than copying. The callee can then make a copy of them only if needed, such as when needing to work with a mutable copy.
In other cases where structures are passed by value, it's also possible for the compiler to specialise functions in order to only copy across the properties that the function needs.
For the following code:
struct Point {
var x: Float = 0
var y: Float = 1
}
func foo(p: Point) {
print(p.x)
}
var p1 = Point()
foo(p: p1)
Assuming foo(p:) isn't inlined by the compiler (it will in this example, but once its implementation reaches a certain size, the compiler won't think it worth it) – the compiler can specialise the function as:
func foo(px: Float) {
print(px)
}
foo(px: 0)
It only passes the value of Point's x property into the function, thereby saving the cost of copying the y property.
So the compiler will do whatever it can in order to reduce the copying of value types. But with so many various optimisations in different circumstances, you cannot simply boil the optimised behaviour of arbitrary value types down to just copy-on-write.

Swift Copy On Write(COW)
Make a copy only when it is necessary(e.g. when we change/write).
By default Value Type[About] does not support COW(Copy on Write) mechanism. But some of system structures like Collections(Array, Dictionary, Set) support it
Print address
// Print memory address
func address(_ object: UnsafeRawPointer) -> String {
let address = Int(bitPattern: object)
return NSString(format: "%p", address) as String
}
Value type default behaviour
struct A {
var value: Int = 0
}
//Default behavior(COW is not used)
var a1 = A()
var a2 = a1
//different addresses
print(address(&a1)) //0x7ffee48f24a8
print(address(&a2)) //0x7ffee48f24a0
//COW for a2 is not used
a2.value = 1
print(address(&a2)) //0x7ffee48f24a0
Value type with COW (Collection)
//collection(COW is realized)
var collection1 = [A()]
var collection2 = collection1
//same addresses
print(address(&collection1)) //0x600000c2c0e0
print(address(&collection2)) //0x600000c2c0e0
//COW for collection2 is used
collection2.append(A())
print(address(&collection2)) //0x600000c2c440
Use COW semantics for large values to minimise copying data every time. There are two common ways:
use a wrapper with value type which support COW.
use a wrapper which has a reference to heap where we can save large data. The point is:
we are able to create multiple copies of lite wrapper which will be pointed to the same large data in a heap
when we try to modify(write) a new reference with a copy of large data will be created - COW in action. AnyObject.isKnownUniquelyReferenced() which can say if there is a
single reference to this object
struct Box<T> {
fileprivate var ref: Ref<T>
init(value: T) {
self.ref = Ref(value: value)
}
var value: T {
get {
return ref.value
}
set {
//it is true when there is only one(single) reference to this object
//that is why it is safe to update,
//if not - new reference to heap is created with a copy of value
if (isKnownUniquelyReferenced(&self.ref)) {
self.ref.value = newValue
} else {
self.ref = Ref(value: newValue)
}
}
}
final class Ref<T> {
var value: T
init(value: T) {
self.value = value
}
}
}
let value = 0
var box1 = Box(value: value)
var box2 = box1
//same addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000ac2490
box2.value = 1
print(box1.value) //0
print(box2.value) //1
//COW in action
//different addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000a9dd30

Related

Copy behavior in composed Swift struct

// definition: Company: { Member { [Activity { times: Int }] }
struct Company {
var bossId: Int = 0
var members: [Int: Member] = [:]
var boss: Member? {
get { return members[bossId] }
set { members[bossId] = newValue }
}
}
struct Member {
var name: String
var activities: [Activity]
}
struct Activity {
var type: String
var times: Int
}
// init
var company = Company()
company.members[0] = Member(name: "John",activities: [Activity(type: "Walk", times: 0)])
company.members[1] = Member(name: "Sean", activities: [Activity(type: "Run", times: 0)])
I have a computed property in my top structure, boss returns one of the members by id. When I want to update the properties of some leaf members, compiler complains it needs a setter. So I add a members[bossId] = newValue setter for it. It seems when value is being mutating, it will assign a new updated Member to replace original Member, because it is struct instead of class.
Does it cause whole copy of struct boss: Member even I just need update one int property of member?
Should I worry this redundant copy? Or compiler is smart enough to minimize impact?
// use
company.boss?.activities[0].times = 1
company.boss?.activities[0].times = 2
company.boss?.activities[0].times = 3 // <- Does it cause 3 times whole `Member` copy?
Keep in mind that Swift structs are extremely cheap to copy - it's just a matter of writing values to a memory location. It's similar to assigning Int values, you don't get a performance penalty if you pass around the value 5.
This of course assumes the struct is not huge, like having hundreds of fields, in which case the actual copy can pose some performance issues, but anyway less than operations that involve heap allocations.
Getting back to your case, your three structs are not big at all:
print("Company:", MemoryLayout<Company>.size) // 16
print("Member:", MemoryLayout<Member>.size) // 24
print("Activity:", MemoryLayout<Activity>.size) // 24
print("Array<Activity>:", MemoryLayout<[Activity]>.size) // 8
So, changing properties on one of those structs is a matter of rewriting 8 to 24 bytes, which happens really fast.
So, with the above in mind, let's break down what happens when you write something like
company.boss?.activities[0].times = 2
This is, roughly, what happens under the hood:
activities[0].times = 2 results in Array updating the times value for the first item in the array
the company.boss?.activities property is replaced by a new instance of Array<Activity>, which means rewriting 8 bytes (the size of the Array struct)
the company.boss property gets replaced with the values after the update from #2, which means a write of 24 bytes
finally, the company itself is rewritten, 16 more bytes
So, in total, the rewrites count for less than 50 bytes, it could be way less depending on how much the compiler optimizes the memory writes. Even if this happens 3 times, like in your example, is still incredibly fast.
P.S. It could be that activities[0].times = 2 to result in another heap allocation, which would have a bigger performance impact, if the Copy-on-write mechanism enters into play. However this is bound to happen regardless how you structure your structs.

How to use inout on array of iVars? [duplicate]

I know that swift will optimize to copy on write for arrays but will it do this for all structs? For example:
struct Point {
var x:Float = 0
}
var p1 = Point()
var p2 = p1 //p1 and p2 share the same data under the hood
p2.x += 1 //p2 now has its own copy of the data
Array is implemented with copy-on-write behaviour – you'll get it regardless of any compiler optimisations (although of course, optimisations can decrease the number of cases where a copy needs to happen).
At a basic level, Array is just a structure that holds a reference to a heap-allocated buffer containing the elements – therefore multiple Array instances can reference the same buffer. When you come to mutate a given array instance, the implementation will check if the buffer is uniquely referenced, and if so, mutate it directly. Otherwise, the array will perform a copy of the underlying buffer in order to preserve value semantics.
However, with your Point structure – you're not implementing copy-on-write at a language level. Of course, as #Alexander says, this doesn't stop the compiler from performing all sorts of optimisations to minimise the cost of copying whole structures about. These optimisations needn't follow the exact behaviour of copy-on-write though – the compiler is simply free to do whatever it wishes, as long as the program runs according to the language specification.
In your specific example, both p1 and p2 are global, therefore the compiler needs to make them distinct instances, as other .swift files in the same module have access to them (although this could potentially be optimised away with whole-module optimisation). However, the compiler still doesn't need to copy the instances – it can just evaluate the floating-point addition at compile-time and initialise one of the globals with 0.0, and the other with 1.0.
And if they were local variables in a function, for example:
struct Point {
var x: Float = 0
}
func foo() {
var p1 = Point()
var p2 = p1
p2.x += 1
print(p2.x)
}
foo()
The compiler doesn't even have to create two Point instances to begin with – it can just create a single floating-point local variable initialised to 1.0, and print that.
Regarding passing value types as function arguments, for large enough types and (in the case of structures) functions that utilise enough of their properties, the compiler can pass them by reference rather than copying. The callee can then make a copy of them only if needed, such as when needing to work with a mutable copy.
In other cases where structures are passed by value, it's also possible for the compiler to specialise functions in order to only copy across the properties that the function needs.
For the following code:
struct Point {
var x: Float = 0
var y: Float = 1
}
func foo(p: Point) {
print(p.x)
}
var p1 = Point()
foo(p: p1)
Assuming foo(p:) isn't inlined by the compiler (it will in this example, but once its implementation reaches a certain size, the compiler won't think it worth it) – the compiler can specialise the function as:
func foo(px: Float) {
print(px)
}
foo(px: 0)
It only passes the value of Point's x property into the function, thereby saving the cost of copying the y property.
So the compiler will do whatever it can in order to reduce the copying of value types. But with so many various optimisations in different circumstances, you cannot simply boil the optimised behaviour of arbitrary value types down to just copy-on-write.
Swift Copy On Write(COW)
Make a copy only when it is necessary(e.g. when we change/write).
By default Value Type[About] does not support COW(Copy on Write) mechanism. But some of system structures like Collections(Array, Dictionary, Set) support it
Print address
// Print memory address
func address(_ object: UnsafeRawPointer) -> String {
let address = Int(bitPattern: object)
return NSString(format: "%p", address) as String
}
Value type default behaviour
struct A {
var value: Int = 0
}
//Default behavior(COW is not used)
var a1 = A()
var a2 = a1
//different addresses
print(address(&a1)) //0x7ffee48f24a8
print(address(&a2)) //0x7ffee48f24a0
//COW for a2 is not used
a2.value = 1
print(address(&a2)) //0x7ffee48f24a0
Value type with COW (Collection)
//collection(COW is realized)
var collection1 = [A()]
var collection2 = collection1
//same addresses
print(address(&collection1)) //0x600000c2c0e0
print(address(&collection2)) //0x600000c2c0e0
//COW for collection2 is used
collection2.append(A())
print(address(&collection2)) //0x600000c2c440
Use COW semantics for large values to minimise copying data every time. There are two common ways:
use a wrapper with value type which support COW.
use a wrapper which has a reference to heap where we can save large data. The point is:
we are able to create multiple copies of lite wrapper which will be pointed to the same large data in a heap
when we try to modify(write) a new reference with a copy of large data will be created - COW in action. AnyObject.isKnownUniquelyReferenced() which can say if there is a
single reference to this object
struct Box<T> {
fileprivate var ref: Ref<T>
init(value: T) {
self.ref = Ref(value: value)
}
var value: T {
get {
return ref.value
}
set {
//it is true when there is only one(single) reference to this object
//that is why it is safe to update,
//if not - new reference to heap is created with a copy of value
if (isKnownUniquelyReferenced(&self.ref)) {
self.ref.value = newValue
} else {
self.ref = Ref(value: newValue)
}
}
}
final class Ref<T> {
var value: T
init(value: T) {
self.value = value
}
}
}
let value = 0
var box1 = Box(value: value)
var box2 = box1
//same addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000ac2490
box2.value = 1
print(box1.value) //0
print(box2.value) //1
//COW in action
//different addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000a9dd30

Mutual non-optional reference cycle in Swift

Consider the following use case:
In a model for some game, you have a Player class. Each Player has an unowned let opponent: Player which represents the opponent they are playing against. These are always created in pairs, and a Player must always have an opponent since it is non-optional. However, this is very difficult to model, since one player must be created before the other, and the first player will not have an opponent until after the second one is created!
Through some ugly hacking, I came up with this solution:
class Player {
private static let placeholder: Player = Player(opponent: .placeholder, name: "")
private init(opponent: Player, name: String) {
self.opponent = opponent
self.name = name
}
unowned var opponent: Player
let name: String
class func getPair(named names: (String, String)) -> (Player, Player) {
let p1 = Player(opponent: .placeholder, name: names.0)
let p2 = Player(opponent: p1, name: names.1)
p1.opponent = p2
return (p1, p2)
}
}
let pair = Player.getPair(named:("P1", "P2"))
print(pair.0.opponent.name)
print(pair.1.opponent.name)
Which works quite well. However, I am having trouble turning opponent into a constant. One solution is to make opponent a computed property without a set, backed by a private var, but I'd like to avoid this.
I attempted to do some hacking with Swift pointers, and came up with:
class func getPair(named names: (String, String)) -> (Player, Player) {
var p1 = Player(opponent: .placeholder, name: names.0 + "FAKE")
let p2 = Player(opponent: p1, name: names.1)
withUnsafeMutablePointer(to: &p1) {
var trueP1 = Player(opponent: p2, name: names.0)
$0.moveAssign(from: &trueP1, count: 1)
}
return (p1, p2)
}
But this gives a segfault. Furthermore, when debugging with lldb, we can see that just after p1 is initialized, we have:
(lldb) p p1
(Player2.Player) $R3 = 0x0000000101004390 {
opponent = 0x0000000100702940 {
opponent = <uninitialized>
name = ""
}
name = "P1FAKE"
}
But at the end of the function, lldb shows this:
(lldb) p p1
(Player2.Player) $R5 = 0x00000001010062d0 {
opponent = 0x00000001010062a0 {
opponent = 0x0000000101004390 {
opponent = 0x0000000100702940 {
opponent = <uninitialized>
name = ""
}
name = "P1FAKE"
}
name = "P2"
}
name = "P1"
}
(lldb) p p2
(Player2.Player) $R4 = 0x00000001010062a0 {
opponent = 0x0000000101004390 {
opponent = 0x0000000100702940 {
opponent = <uninitialized>
name = ""
}
name = "P1FAKE"
}
name = "P2"
}
So p1 correctly points to p2, but p2 still points to the old p1. What's more, p1 has actually changed addresses!
My question is two-fold:
Is there a cleaner, more 'Swifty' way to create this structure of mutual non-optional references?
If not, what am I misunderstanding about UnsafeMutablePointers and the like in Swift that makes the above code not work?
I think an implicitly unwrapped optional is what you want. You declare it with an exclamation mark (!). It's a promise to the compiler that even though the property may be initialized during the init call, it will have a valid value when you use it. Combining this with a private setter, you can achieve what you want:
class Player: CustomStringConvertible {
var name: String
private(set) weak var opponent: Player!
init(name: String) {
self.name = name
}
class func getPair(named names: (String, String)) -> (Player, Player) {
let p1 = Player(name: names.0)
let p2 = Player(name: names.1)
p1.opponent = p2
p2.opponent = p1
return (p1, p2)
}
var description: String {
return self.name
}
}
let (p1, p2) = Player.getPair(named: ("Player One", "Player Two"))
print(p1.opponent) // Player Two
print(p2.opponent) // Player One
Since the setter is private the compiler will throw an error if you try to change it:
let p3 = Player(name: "Player Three")
p1.opponent = p3 // Error: Cannot assign to property: 'opponent' setter is inaccessible
Note that since you intended for getPair to be the single method to create a Player instance, you may as well set the init call to private since it doesn't set the opponent property:
private init(name: String) {
// ...
}
After messing with this for a while it seems what you're wanting to do is likely not possible, and doesn't really jive with Swift. More importantly, it's likely a flawed approach to begin with.
As far as Swift goes, initializers are required to initialize all stored values before they return. This is for a number of reasons I won't go into. Optionals, IUOs, and computed values are used when a value cannot be guaranteed/calculated at initialization. If you don't want Optionals, IUOs or computed values but still want some stored values to be unset after init, you're wanting to have your cake and eat it too.
As far as the design, if you need two objects to be linked so tightly as to require each other at initialization, your model is (IMO) broken. This is the exact problem hierarchical data structures solve so well. In your specific example, it seems clear you need some sort of Match or Competition object that creates and manages the relationship between the two players, I know your question is closer to "is this possible" not "should it be done", but I can't think of any situation where this isn't a bad idea. Fundamentally it breaks encapsulation.
The Player object should manage and track the things that exist within a Player object, and the only managed relationships within the Player class should be with it's children. Any sibling relationship should be accessed/set by it's parent.
This becomes a clearer problem with scale. What if you want to add a third player? what about 50? You will then have to initialize and connect every single player to ever other before you can use any of the players. If you want to add or remove a player, you will have to do it for every single connected player simultaneously, and block anything from happening while that takes place.
Another issues is it makes it unusable in any other situation. If designed properly, a Player could be used in all types of games. Whereas the current design allowed it to be used only in a 1v1 situation. For any other case you would have to re-write it and your code base would diverge.
In summation, what you want is probably not possible in Swift, but if or when it becomes possible, it's almost certainly a bad idea anyway :)
Sorry for the essay, hope you find it helpful!
There is a way to do this cleanly in Swift using lazy properties (for a convenient API) and a container that contains both players (for sane memory management). For a TL;DR, take a look at the example code below. For a longer answer, read on:
By definition, a cycle between two objects must be optional in nature in Swift because:
Swift dictates that all fields of an object need to be initialized by the time the the object's initializer has executed. So, an optional, or an implicitly unwrapped optional reference, or an unowned reference are your options if you want to tie together two objects with references (both need initialization, so at least one exists before its opponent).
If the objects are of a class type, then they should be weakly referenced, and again, weak references are by definition optional in nature (either automatically zeroed and implicit or explicit).
Being able to create a pair of dynamically allocated objects like what you are after is really more natural in an environment with a garbage collector (Swift uses automated reference counting which simply leaks your pair of objects if it goes unrooted from your code). Some kind of container that contains both players is therefore useful (if not absolutely necessary) in Swift.
I would argue that even despite the language limitations which prevent you from doing what you are trying on initialization time, your model has other problems which would benefit from a hierarchy of two levels.
If a player only ever exists in context of another player, you should only ever be able to create a maximum of two of them per match.
You may want to also define an order to the players, for instance to decide who starts if it is a turn based game, or to define for presentation purposes one of the players as playing a "home" match, etc.
Both of the above concerns, especially the first, is really pointing clearly to the utility of some kind of container object that would handle the initialization of your Players (i.e. only that container would know how to initialize a Player, and would be able to bind all the mutable properties together). This container (Match) in the below example code is one where I placed an opponent(for:Player) method to query for the opponent for a player. This method gets called in the lazy opponent property of Player.
public class Match {
public enum PlayerIndex {
case first
case second
}
private(set) var players:PlayerPair
init(players:PlayerNamePair) {
// match needs to be first set to nil because Match fields need setting before 'self' can be referenced.
self.players = (Player(match: nil, name: players.A, index: .first),
Player(match: nil, name: players.A, index: .second))
// then set the 'match' reference in the Player objects.
self.players.A.match = self
self.players.B.match = self
}
public func opponent(for player:Player) -> Player {
switch (player.index) {
case .first:
return self.players.B
case .second:
return self.players.A
}
}
/* Player modelled here as a nested type to a Match.
* That's just a personal preference, but incidental to the question posted. */
typealias PlayerNamePair = (A:String, B:String)
typealias PlayerPair = (A:Player, B:Player)
public class Player {
public let name:String
fileprivate let index:PlayerIndex
fileprivate weak var match:Match?
/* This init method is only visible inside the file, and only called by Match initializer. */
fileprivate init(match:Match?, name:String, index:PlayerIndex) {
self.name = name
self.match = match
self.index = index
}
/* We dare implicitly unwrap here because Player initialization and lifecycle
* is controlled by the containing Match.
*
* That is, Players only ever exists in context of an owning match,
* therefore it's OK to treat it as a bug which crashes reproducibly
* if you query for the opponent for the first time only after the match (which we know to have been non-nil) has already been deallocated. */
public lazy var opponent:Player = public lazy var opponent:Player = self.match!.opponent(for: self)
}
}

Capturing a struct reference in a closure doesn't allow mutations to occur

I am trying to see if I can use structs for my model and was trying this. When I call vm.testClosure(), it does not change the value of x and I am not sure why.
struct Model
{
var x = 10.0
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
testClosure =
{
() -> () in
model.x = 30.5
}
}
}
var vm = ViewModel(model:&m)
m.x
vm.testClosure()
m.x
An inout argument isn't a reference to a value type – it's simply a shadow copy of that value type, that is written back to the caller's value when the function returns.
What's happening in your code is that your inout variable is escaping the lifetime of the function (by being captured in a closure that is then stored) – meaning that any changes to the inout variable after the function has returned will never be reflected outside that closure.
Due to this common misconception about inout arguments, there has been a Swift Evolution proposal for only allowing inout arguments to be captured by #noescape closures. As of Swift 3, your current code will no longer compile.
If you really need to be passing around references in your code – then you should be using reference types (make your Model a class). Although I suspect that you'll probably be able to refactor your logic to avoid passing around references in the first place (however without seeing your actual code, it's impossible to advise).
(Edit: Since posting this answer, inout parameters can now be compiled as a pass-by-reference, which can be seen by looking at the SIL or IR emitted. However you are unable to treat them as such due to the fact that there's no guarantee whatsoever that the caller's value will remain valid after the function call.)
Instances of the closure will get their own, independent copy of the captured value that it, and only it, can alter. The value is captured in the time of executing the closure. Let see your slightly modified code
struct Model
{
var x = 10.0
mutating func modifyX(newValue: Double) {
let this = self
let model = m
x = newValue
// put breakpoint here
//(lldb) po model
//▿ Model
// - x : 30.0
//
//(lldb) po self
//▿ Model
// - x : 301.0
//
//(lldb) po this
//▿ Model
// - x : 30.0
}
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
model.x = 50
testClosure =
{ () -> () in
model.modifyX(301)
}
model.x = 30
}
}
let mx = m.x
vm.testClosure()
let mx2 = m.x
Here is what Apple says about that.
Classes and Structures
A value type is a type that is copied when it is assigned to a
variable or constant, or when it is passed to a function. [...] All
structures and enumerations are value types in Swift
Methods
Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
However, if you need to modify the properties of your structure or
enumeration within a particular method, you can opt in to mutating
behaviour for that method. The method can then mutate (that is,
change) its properties from within the method, and any changes that it
makes are written back to the original structure when the method ends.
The method can also assign a completely new instance to its implicit
self property, and this new instance will replace the existing one
when the method ends.
Taken from here

Why Choose Struct Over Class?

Playing around with Swift, coming from a Java background, why would you want to choose a Struct instead of a Class? Seems like they are the same thing, with a Struct offering less functionality. Why choose it then?
According to the very popular WWDC 2015 talk Protocol Oriented Programming in Swift (video, transcript), Swift provides a number of features that make structs better than classes in many circumstances.
Structs are preferable if they are relatively small and copiable because copying is way safer than having multiple references to the same instance as happens with classes. This is especially important when passing around a variable to many classes and/or in a multithreaded environment. If you can always send a copy of your variable to other places, you never have to worry about that other place changing the value of your variable underneath you.
With Structs, there is much less need to worry about memory leaks or multiple threads racing to access/modify a single instance of a variable. (For the more technically minded, the exception to that is when capturing a struct inside a closure because then it is actually capturing a reference to the instance unless you explicitly mark it to be copied).
Classes can also become bloated because a class can only inherit from a single superclass. That encourages us to create huge superclasses that encompass many different abilities that are only loosely related. Using protocols, especially with protocol extensions where you can provide implementations to protocols, allows you to eliminate the need for classes to achieve this sort of behavior.
The talk lays out these scenarios where classes are preferred:
Copying or comparing instances doesn't make sense (e.g., Window)
Instance lifetime is tied to external effects (e.g., TemporaryFile)
Instances are just "sinks"--write-only conduits to external state (e.g.CGContext)
It implies that structs should be the default and classes should be a fallback.
On the other hand, The Swift Programming Language documentation is somewhat contradictory:
Structure instances are always passed by value, and class
instances are always passed by reference. This means that they are
suited to different kinds of tasks. As you consider the data
constructs and functionality that you need for a project, decide
whether each data construct should be defined as a class or as a
structure.
As a general guideline, consider creating a structure when one or more
of these conditions apply:
The structure’s primary purpose is to encapsulate a few relatively simple data values.
It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an
instance of that structure.
Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced.
The structure does not need to inherit properties or behavior from another existing type.
Examples of good candidates for structures include:
The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double.
A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int.
A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double.
In all other cases, define a class, and create instances of that class
to be managed and passed by reference. In practice, this means that
most custom data constructs should be classes, not structures.
Here it is claiming that we should default to using classes and use structures only in specific circumstances. Ultimately, you need to understand the real world implication of value types vs. reference types and then you can make an informed decision about when to use structs or classes. Also, keep in mind that these concepts are always evolving and The Swift Programming Language documentation was written before the Protocol Oriented Programming talk was given.
This answer was originally about difference in performance between struct and class. Unfortunately there are too much controversy around the method I used for measuring. I left it below, but please don't read too much into it. I think after all these years, it has become clear in Swift community that struct (along with enum) is always preferred due to its simplicity and safety.
If performance is important to your app, do measure it yourself. I still think most of the time struct performance is superior, but the best answer is just as someone said in the comments: it depends.
=== OLD ANSWER ===
Since struct instances are allocated on stack, and class instances are allocated on heap, structs can sometimes be drastically faster.
However, you should always measure it yourself and decide based on your unique use case.
Consider the following example, which demonstrates 2 strategies of wrapping Int data type using struct and class. I am using 10 repeated values are to better reflect real world, where you have multiple fields.
class Int10Class {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
struct Int10Struct {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
func + (x: Int10Class, y: Int10Class) -> Int10Class {
return IntClass(x.value + y.value)
}
func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
return IntStruct(x.value + y.value)
}
Performance is measured using
// Measure Int10Class
measure("class (10 fields)") {
var x = Int10Class(0)
for _ in 1...10000000 {
x = x + Int10Class(1)
}
}
// Measure Int10Struct
measure("struct (10 fields)") {
var y = Int10Struct(0)
for _ in 1...10000000 {
y = y + Int10Struct(1)
}
}
func measure(name: String, #noescape block: () -> ()) {
let t0 = CACurrentMediaTime()
block()
let dt = CACurrentMediaTime() - t0
print("\(name) -> \(dt)")
}
Code can be found at https://github.com/knguyen2708/StructVsClassPerformance
UPDATE (27 Mar 2018):
As of Swift 4.0, Xcode 9.2, running Release build on iPhone 6S, iOS 11.2.6, Swift Compiler setting is -O -whole-module-optimization:
class version took 2.06 seconds
struct version took 4.17e-08 seconds (50,000,000 times faster)
(I no longer average multiple runs, as variances are very small, under 5%)
Note: the difference is a lot less dramatic without whole module optimization. I'd be glad if someone can point out what the flag actually does.
UPDATE (7 May 2016):
As of Swift 2.2.1, Xcode 7.3, running Release build on iPhone 6S, iOS 9.3.1, averaged over 5 runs, Swift Compiler setting is -O -whole-module-optimization:
class version took 2.159942142s
struct version took 5.83E-08s (37,000,000 times faster)
Note: as someone mentioned that in real-world scenarios, there will be likely more than 1 field in a struct, I have added tests for structs/classes with 10 fields instead of 1. Surprisingly, results don't vary much.
ORIGINAL RESULTS (1 June 2014):
(Ran on struct/class with 1 field, not 10)
As of Swift 1.2, Xcode 6.3.2, running Release build on iPhone 5S, iOS 8.3, averaged over 5 runs
class version took 9.788332333s
struct version took 0.010532942s (900 times faster)
OLD RESULTS (from unknown time)
(Ran on struct/class with 1 field, not 10)
With release build on my MacBook Pro:
The class version took 1.10082 sec
The struct version took 0.02324 sec (50 times faster)
Similarities between structs and classes.
I created gist for this with simple examples.
https://github.com/objc-swift/swift-classes-vs-structures
And differences
1. Inheritance.
structures can't inherit in swift. If you want
class Vehicle{
}
class Car : Vehicle{
}
Go for an class.
2. Pass By
Swift structures pass by value and class instances pass by reference.
Contextual Differences
Struct constant and variables
Example (Used at WWDC 2014)
struct Point{
var x = 0.0;
var y = 0.0;
}
Defines a struct called Point.
var point = Point(x:0.0,y:2.0)
Now if I try to change the x. Its a valid expression.
point.x = 5
But if I defined a point as constant.
let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.
In this case entire point is immutable constant.
If I used a class Point instead this is a valid expression. Because in a class immutable constant is the reference to the class itself not its instance variables (Unless those variables defined as constants)
Assuming that we know Struct is a value type and Class is a reference type.
If you don't know what a value type and a reference type are then see What's the difference between passing by reference vs. passing by value?
Based on mikeash's post:
... Let's look at some extreme, obvious examples first. Integers are
obviously copyable. They should be value types. Network sockets can't
be sensibly copied. They should be reference types. Points, as in x, y
pairs, are copyable. They should be value types. A controller that
represents a disk can't be sensibly copied. That should be a reference
type.
Some types can be copied but it may not be something you want to
happen all the time. This suggests that they should be reference
types. For example, a button on the screen can conceptually be copied.
The copy will not be quite identical to the original. A click on the
copy will not activate the original. The copy will not occupy the same
location on the screen. If you pass the button around or put it into a
new variable you'll probably want to refer to the original button, and
you'd only want to make a copy when it's explicitly requested. That
means that your button type should be a reference type.
View and window controllers are a similar example. They might be
copyable, conceivably, but it's almost never what you'd want to do.
They should be reference types.
What about model types? You might have a User type representing a user
on your system, or a Crime type representing an action taken by a
User. These are pretty copyable, so they should probably be value
types. However, you probably want updates to a User's Crime made in
one place in your program to be visible to other parts of the program.
This suggests that your Users should be managed by some sort of user
controller which would be a reference type. e.g
struct User {}
class UserController {
var users: [User]
func add(user: User) { ... }
func remove(userNamed: String) { ... }
func ...
}
Collections are an interesting case. These include things like arrays
and dictionaries, as well as strings. Are they copyable? Obviously. Is
copying something you want to happen easily and often? That's less
clear.
Most languages say "no" to this and make their collections reference
types. This is true in Objective-C and Java and Python and JavaScript
and almost every other language I can think of. (One major exception
is C++ with STL collection types, but C++ is the raving lunatic of the
language world which does everything strangely.)
Swift said "yes," which means that types like Array and Dictionary and
String are structs rather than classes. They get copied on assignment,
and on passing them as parameters. This is an entirely sensible choice
as long as the copy is cheap, which Swift tries very hard to
accomplish.
...
I personally don't name my classes like that. I usually name mine UserManager instead of UserController but the idea is the same
In addition don't use class when you have to override each and every instance of a function ie them not having any shared functionality.
So instead of having several subclasses of a class. Use several structs that conform to a protocol.
Another reasonable case for structs is when you want to do a delta/diff of your old and new model. With references types you can't do that out of the box. With value types the mutations are not shared.
Here are some other reasons to consider:
structs get an automatic initializer that you don't have to maintain in code at all.
struct MorphProperty {
var type : MorphPropertyValueType
var key : String
var value : AnyObject
enum MorphPropertyValueType {
case String, Int, Double
}
}
var m = MorphProperty(type: .Int, key: "what", value: "blah")
To get this in a class, you would have to add the initializer, and maintain the intializer...
Basic collection types like Array are structs. The more you use them in your own code, the more you will get used to passing by value as opposed to reference. For instance:
func removeLast(var array:[String]) {
array.removeLast()
println(array) // [one, two]
}
var someArray = ["one", "two", "three"]
removeLast(someArray)
println(someArray) // [one, two, three]
Apparently immutability vs. mutability is a huge topic, but a lot of smart folks think immutability -- structs in this case -- is preferable. Mutable vs immutable objects
Some advantages:
automatically threadsafe due to not being shareable
uses less memory due to no isa and refcount (and in fact is stack allocated generally)
methods are always statically dispatched, so can be inlined (though #final can do this for classes)
easier to reason about (no need to "defensively copy" as is typical with NSArray, NSString, etc...) for the same reason as thread safety
Structs are value type and Classes are reference type
Value types are faster than Reference types
Value type instances are safe in a multi-threaded environment as
multiple threads can mutate the instance without having to worry
about the race conditions or deadlocks
Value type has no references unlike reference type; therefore there
is no memory leaks.
Use a value type when:
You want copies to have independent state, the data will be used in
code across multiple threads
Use a reference type when:
You want to create shared, mutable state.
Further information could be also found in the Apple documentation
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
Additional Information
Swift value types are kept in the stack. In a process, each thread has its own stack space, so no other thread will be able to access your value type directly. Hence no race conditions, locks, deadlocks or any related thread synchronization complexity.
Value types do not need dynamic memory allocation or reference counting, both of which are expensive operations. At the same time methods on value types are dispatched statically. These create a huge advantage in favor of value types in terms of performance.
As a reminder here is a list of Swift
Value types:
Struct
Enum
Tuple
Primitives (Int, Double, Bool etc.)
Collections (Array, String, Dictionary, Set)
Reference types:
Class
Anything coming from NSObject
Function
Closure
Structure is much more faster than Class. Also, if you need inheritance then you must use Class. Most important point is that Class is reference type whereas Structure is value type. for example,
class Flight {
var id:Int?
var description:String?
var destination:String?
var airlines:String?
init(){
id = 100
description = "first ever flight of Virgin Airlines"
destination = "london"
airlines = "Virgin Airlines"
}
}
struct Flight2 {
var id:Int
var description:String
var destination:String
var airlines:String
}
now lets create instance of both.
var flightA = Flight()
var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )
now lets pass these instance to two functions which modify the id, description, destination etc..
func modifyFlight(flight:Flight) -> Void {
flight.id = 200
flight.description = "second flight of Virgin Airlines"
flight.destination = "new york"
flight.airlines = "Virgin Airlines"
}
also,
func modifyFlight2(flight2: Flight2) -> Void {
var passedFlight = flight2
passedFlight.id = 200
passedFlight.description = "second flight from virgin airlines"
}
so,
modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)
now if we print the flightA's id and description, we get
id = 200
description = "second flight of Virgin Airlines"
Here, we can see the id and description of FlightA is changed because the parameter passed to the modify method actually points to the memory address of flightA object(reference type).
now if we print the id and description of FLightB instance we get,
id = 100
description = "first ever flight of Virgin Airlines"
Here we can see that the FlightB instance is not changed because in modifyFlight2 method, actual instance of Flight2 is passes rather than reference ( value type).
Answering the question from the perspective of value types vs reference types, from this Apple blog post it would appear very simple:
Use a value type [e.g. struct, enum] when:
Comparing instance data with == makes sense
You want copies to have independent state
The data will be used in code across multiple threads
Use a reference type [e.g. class] when:
Comparing instance identity with === makes sense
You want to create shared, mutable state
As mentioned in that article, a class with no writeable properties will behave identically with a struct, with (I will add) one caveat: structs are best for thread-safe models -- an increasingly imminent requirement in modern app architecture.
Struct vs Class
[Stack vs Heap]
[Value vs Reference type]
Struct is more preferable. But Struct does not solve all issues by default. Usually you can hear that value type is allocated on stack, but it is not always true. Only local variables are allocated on stack
//simple blocks
struct ValueType {}
class ReferenceType {}
struct StructWithRef {
let ref1 = ReferenceType()
}
class ClassWithRef {
let ref1 = ReferenceType()
}
func foo() {
//simple blocks
let valueType1 = ValueType()
let refType1 = ReferenceType()
//RetainCount
//StructWithRef
let structWithRef1 = StructWithRef()
let structWithRef1Copy = structWithRef1
print("original:", CFGetRetainCount(structWithRef1 as CFTypeRef)) //1
print("ref1:", CFGetRetainCount(structWithRef1.ref1)) //2 (originally 3)
//ClassWithRef
let classWithRef1 = ClassWithRef()
let classWithRef1Copy = classWithRef1
print("original:", CFGetRetainCount(classWithRef1)) //2 (originally 3)
print("ref1:", CFGetRetainCount(classWithRef1.ref1)) //1 (originally 2)
}
*You should not use/rely on retainCount, because it does not say useful information
To check stack or heap
During compiling SIL(Swift Intermediate Language) can optimize you code
swiftc -emit-silgen -<optimization> <file_name>.swift
//e.g.
swiftc -emit-silgen -Onone file.swift
//emit-silgen -> emit-sil(is used in any case)
//-emit-silgen Emit raw SIL file(s)
//-emit-sil Emit canonical SIL file(s)
//optimization: O, Osize, Onone. It is the same as Swift Compiler - Code Generation -> Optimization Level
There you can find alloc_stack(allocation on stack) and alloc_box(allocation on heap)
[Optimization Level(SWIFT_OPTIMIZATION_LEVEL)]
With classes you get inheritance and are passed by reference, structs do not have inheritance and are passed by value.
There are great WWDC sessions on Swift, this specific question is answered in close detail in one of them. Make sure you watch those, as it will get you up to speed much more quickly then the Language guide or the iBook.
I wouldn't say that structs offer less functionality.
Sure, self is immutable except in a mutating function, but that's about it.
Inheritance works fine as long as you stick to the good old idea that every class should be either abstract or final.
Implement abstract classes as protocols and final classes as structs.
The nice thing about structs is that you can make your fields mutable without creating shared mutable state because copy on write takes care of that :)
That's why the properties / fields in the following example are all mutable, which I would not do in Java or C# or swift classes.
Example inheritance structure with a bit of dirty and straightforward usage at the bottom in the function named "example":
protocol EventVisitor
{
func visit(event: TimeEvent)
func visit(event: StatusEvent)
}
protocol Event
{
var ts: Int64 { get set }
func accept(visitor: EventVisitor)
}
struct TimeEvent : Event
{
var ts: Int64
var time: Int64
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
}
protocol StatusEventVisitor
{
func visit(event: StatusLostStatusEvent)
func visit(event: StatusChangedStatusEvent)
}
protocol StatusEvent : Event
{
var deviceId: Int64 { get set }
func accept(visitor: StatusEventVisitor)
}
struct StatusLostStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var reason: String
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
struct StatusChangedStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var newStatus: UInt32
var oldStatus: UInt32
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
func readEvent(fd: Int) -> Event
{
return TimeEvent(ts: 123, time: 56789)
}
func example()
{
class Visitor : EventVisitor
{
var status: UInt32 = 3;
func visit(event: TimeEvent)
{
print("A time event: \(event)")
}
func visit(event: StatusEvent)
{
print("A status event: \(event)")
if let change = event as? StatusChangedStatusEvent
{
status = change.newStatus
}
}
}
let visitor = Visitor()
readEvent(1).accept(visitor)
print("status: \(visitor.status)")
}
In Swift, a new programming pattern has been introduced known as Protocol Oriented Programming.
Creational Pattern:
In swift, Struct is a value types which are automatically cloned. Therefore we get the required behavior to implement the prototype pattern for free.
Whereas classes are the reference type, which is not automatically cloned during the assignment. To implement the prototype pattern, classes must adopt the NSCopying protocol.
Shallow copy duplicates only the reference, that points to those objects whereas deep copy duplicates object’s reference.
Implementing deep copy for each reference type has become a tedious task. If classes include further reference type, we have to implement prototype pattern for each of the references properties. And then we have to actually copy the entire object graph by implementing the NSCopying protocol.
class Contact{
var firstName:String
var lastName:String
var workAddress:Address // Reference type
}
class Address{
var street:String
...
}
By using structs and enums, we made our code simpler since we don’t have to implement the copy logic.
Many Cocoa APIs require NSObject subclasses, which forces you into using class. But other than that, you can use the following cases from Apple’s Swift blog to decide whether to use a struct / enum value type or a class reference type.
https://developer.apple.com/swift/blog/?id=10
One point not getting attention in these answers is that a variable holding a class vs a struct can be a let while still allowing changes on the object's properties, while you cannot do this with a struct.
This is useful if you don't want the variable to ever point to another object, but still need to modify the object, i.e. in the case of having many instance variables that you wish to update one after another. If it is a struct, you must allow the variable to be reset to another object altogether using var in order to do this, since a constant value type in Swift properly allows zero mutation, while reference types (classes) don't behave this way.
As struct are value types and you can create the memory very easily which stores into stack.Struct can be easily accessible and after the scope of the work it's easily deallocated from the stack memory through pop from the top of the stack.
On the other hand class is a reference type which stores in heap and changes made in one class object will impact to other object as they are tightly coupled and reference type.All members of a structure are public whereas all the members of a class are private.
The disadvantages of struct is that it can't be inherited .
Structure and class are user defied data types
By default, structure is a public whereas class is private
Class implements the principal of encapsulation
Objects of a class are created on the heap memory
Class is used for re usability whereas structure is used for grouping
the data in the same structure
Structure data members cannot be initialized directly but they can be
assigned by the outside the structure
Class data members can be initialized directly by the parameter less
constructor and assigned by the parameterized constructor