Struct vs Class
This post is about two types in Swift, struct
and class
.
I won’t be covering any obvious points about them. You can refer to excellent swift doc here.
Though, what I will cover is the nuanced difference between the two and when should you use each.
First, struct
struct
derives from word structure in that struct
gives a structure to a set of values. It is a container. A container’s identity is frivolous. What matters is what this container contains.
This is an important note. What gives meaning to struct
is its values, not the struct
itself. It simply exists to contain those values in a more structured way, no more, no less.
class
is an enhanced version of struct
. class
is an Object-Oriented concept and class
is what makes of an object. Unlike struct
, class
’s identity actually matters because it is an ‘object’, not just a container of values.
Sure, object can and do contain values but those values only serve to complement, represent the identity of the given class
. Those values mean nothing without the context of the given class
. This is unlike struct
where each value contained in struct
are values that are still meaningful even outside the context of given struct
.
Grasping these nuanced differences properly will help branching out to their use cases.
Okay, so enough with the terminologies. Let’s zoom straight down into our focus here, Swift.
In Swift, struct
and class
are different in a few ways but most distinct of all is the way the two are passed around.
struct
is passed by values while class
is passed by references. This distinction rhymes well with our understanding about struct
and class
.
struct
is a simple container with values in it so it would be quite stupid to be implemented with passed by reference considering all the overheads associated with keeping references, concurrency issues etc.
class
is a representation of an object and therefore, it makes sense to be implemented with passed by reference since the Identity of the class
actually matters.
Let me give you an example.
Think struct
as something like 3D coordinate. You need X, Y, Z values and it will be less organized and therefore more cumbersome to maintain if you were to keep all the values not contained. This is perfect use case for struct
.
Declaration of 3D Coordinate itself doesn’t mean anything significant. What matters is the X, Y, Z values that are contained within.
Think class
as an object in real life (as that really is the gist of Object-Oriented Programming). Let’s say cat. class
cat is an abstracted representation of all the objects that look, behave etc like cat. And its identity matters.
Tom’s cat and Jessica’s cat are clearly two different objects and you should treat in such a way. This is why class
instances are implemented with passed by reference. Whether Tom’s cat is in California or Siberia, it still is Tom’s cat and its identity doesn’t & shouldn’t change. Thus, we keep our reference to that cat wherever it goes (i.e. wherever that class instance is passed to).
Another noticeable distinction has to do with initializer.
struct
gets default initializer if no custom initializer is defined while class
gets one only if one has no properties defined (or more like properties that need to be populated).
struct 3DCoordinate {
let x: Int
let y: Int
let z: Int
}
With the above setting, you get default initializer for it, which is,
let coord = 3DCoordinate(x: 10, y: 10, z: 10)
In class
, you don’t.
This difference in implementation also stems from the conceptual difference that we’ve expounded previously.
struct
exists to contain values. Thus, it makes sense to get default initializer to pass those values.
class
exists to more than just contain values. You might get values from your CoreData
, NSUserDefaults
or do some complex operation on passed values before assigning property values. Thus, you get no default initializer since in most cases, your initializer won’t be as simple as assigning passed values into your properties anyway.
Take-away
Use struct
if you just need a container to put some values in and pass around without concurrency issue.
Personally, I use struct
whenever a consistency needs to be enforced while passing around multiple values. Kind of like protocol
but to serve values. Instead of passing dictionary of values (which is very limited in type-checking), I pass struct
of values.
Use class
for all else.
Addendum
Also, struct
doesn’t support inheritance. If you need that, use class
.