Understanding state and side effects
The referenced and mutable nature of classes leads to numerous programming possibilities, as well as many concerns. If you update a class instance with a new value, then every reference to that instance will also see the new value.
You can use this to your advantage. Perhaps you pass a Student instance to a sports team, a report card and a class roster. Imagine all of these entities need to know the student’s grades, and because they all point to the same instance, they’ll all see new grades as the instance automatically records them.
The result of this sharing is that class instances have state. Changes in state can sometimes be obvious, but often they’re not.
To illustrate this, consider the following code which introduces a side effect:
class Student {
// …
var credits = 0.0
func recordGrade(_ grade: Grade) { grades.append(grade)
credits += grade.credits
}
}
In this slightly modified example of Student, recordGrade(:) now adds the number of credits to the credits property. Calling recordGrade(:) has the side effect of updating credits.
Now, observe how side effects can result in non-obvious behavior:
jane.credits // 7
// The teacher made a mistake; math has 5 credits math = Grade(letter: "A", points: 20.0, credits: 5.0) jane.recordGrade(math)
jane.credits // 12, not 8!
Whoever wrote the modified Student class did so somewhat naïvely by assuming that the same grade won’t get recorded twice! Because a class can modify itself, you need to be careful about unexpected behavior around shared references.
While confusing in a small example such as this, mutability and state could be extremely jarring as classes grow in size and complexity. Situations like this would
be much more common with a Student class that scales to 20 stored properties and has 10 methods.