Swift is a programming language that strongly emphasizes value types. Structs and Enums are first class citizens in Swift. While value types do not support inheritance, they contain properties, methods and extensions, features usually related to classes.
Value types usually don’t manipulate the data they store. It is the owner of that value type that manipulates the data stored in the value. The value type itself can contain interface and convenience methods for computation and calculations using the stored data. This results in a clean and predictable control flow.
Assigning one value type variable to another copies the contained value, while the assignment of reference type variables copies a reference to the object but not the object itself.
This makes value types great for use in multithreaded environments. Sending values among threads results in each thread operating on a copy of that value, meaning there is no implicit sharing inherent to classes where two or more objects can share the same instance which can cause many issues, especially in multithreaded environments. Since every thread has a copy of the original value, changing the original value will not affect the values used on other threads.
The copying nature of value types make them also great and convenient for local reasoning. When you look at certain scope of the code in a project, you don’t have to think about how the rest of that code interacts with that one function. There are no issues with that value type being mutated from somewhere else since there is no implicit sharing. Also, if you need to change a value, you don’t have to worry about changing it for someone else.
Of course, there are advantages to allow implicit sharing, i.e. allowing an object to have multiple owners. When this is not necessary, going with implicit sharing will eventually cause problems and bugs that are harder to track down and fix. It also makes the code harder to understand and follow the control flow because you don’t know where all the owners may be and when one or more of the owners may mutate the values. Working with value types you’ll always know that you are the only owner of that value. This makes reasoning about the code much easier.
In general you should use a struct if it does not need multiple owners, it’s going to encapsulate other value types that are also going to be copied when assigned or passed and you do not need any inherited properties or behavior from another existing type. It’s also good practice to make structs conform to Equatable protocol. Comparison for equality and inequality is natural for value types. It’s also useful to test if certain value type is contained in an array and so on.
If you need multiple owners, inherited properties or behavior, copying or comparing doesn’t make sense (e.g. UIWindow), instance lifetime is tied to external effects (e.g. temporary files) you should consider classes.
If you liked this blog post I’d appreciate if you followed me on Twitter