Clean code: when to use "self." in Swift, and when not to
Hi from the codebug,
Swift is great programming language. We love that it's fast, safe and flexible. We also love it's ability to do inference, taking overhead out of programming. Take this class for example:
class Animal {
var name: String?
func sayName() {
print(name)
}
}
The compiler is able to infer that the sayName
function uses the name
instance variable so instead of forcing us to write print(self.name)
we can simply write print(name)
. Swift also allows us to use the self.
version. So the question is should we use self.
, should we never use it, or is it something in between? Let's examine the options:
Always using
self.
to access instance members and functions.
This is acceptable but has pitfalls. Consider using a closure. Closures retain their references by default with astrong
relationship. This means, you risk causing memory leaks when not careful. The Swift compiler warns you of this implicit behaviour by forcingself.
for property access in closures. But if you useself.
everywhere, you won't even notice when a closure also usesself.
and you could fall prey to a memory leak without noticing this. This just happened to us. You lose this precious information by usingself.
everywhere and instead gain a lot of noise.Using
self.
only when the compiler needs it.
This means using self in closures (to show strong ownership) and initialisers (to resolve ambiguity). This wayself.
becomes the exceptional occurrence rather than the common and it is no longer a useless word, it tells the programmer the compiler is doing something special with this variable so pay attention. Rather than a noise word used everywhere out of habit in Objective C (where usage ofself.
was needed to access variables through setters and getters) it becomes something meaningful and useful to the programer's eye.
Conclusion: Use self.
carefully and only when you need it.
This will go into my code style guide for Swift, and I hope in time it will be considered best practice in the community.
PS: I initially wanted self.
to be mandated everywhere. I even supported this Swift mailing list proposal to mandate it everywhere for the reasons explained below. Fortunately the team behind Swift saw further than we did and made the right balance between brevity and clarity.
PPS: I still think that when reading Swift Pull Requests you are sometimes confused if something is an iVar or global variable because they look the same. Mandating self.
access for iVars would solve that. But it would also bring visual noise and repetition which Swift doesn't stand for. It'a tradeoff and the team choose the right balance.