Let’s think that compile-time errors and run-time errors are like twins! Compile-time errors are the 😇 (innocent ones) and run-time errors are the 😈 (evil ones). Compile-time errors will help us avoid any mistakes that could cause their evil twins i.e. run-time errors to bug our product. This is the first post of my multi-part blog series for Swift developers. I’ll be sharing couple of instances on how we can leverage compile-time errors to design our classes or methods in a way that causes compile-time errors more often when someone interacts with them!
Lets see an example to understand what I mean..
Objective — We have to create an
User class which has two properties,
lastName. The naive way of designing it would be..
..and to create a new
user object we could simply write..
let user = User()
Seems harmless for now as we don’t get any warnings/errors from our compiler friend. We think all went good but when we try to access one of its property say
firstName it crashes bad at run-time 😱.
Something went wrong.. and as we can see the value of
firstName is nil. It’s because we made our
user object without initialising its
lastName and for some reason the compiler couldn’t warn us either 😕. Lets see what’s going on and try to refactor it..
We could start by throwing away the unnecessary
! (bang operator). Wait.. why its unnecessary here 🤔 ? Before we remove let’s talk about it..
var firstName: String!
..simply tells the compiler that it doesn’t need to worry about whether it should throw us any warning/error messages while accessing
firstName. Compiler can dangerously assume that this variable will have some value all the time 😒 and will crash silently if we don’t assign any value before its accessed! 😈 twin gets excited whenever we use
! operator as its not safe and should only be used on advise 👊.
Now that we have removed it, lets try to build..
..aaaaand the 😇 twin is happy now by showing us some error — not having initialised all the stored properties. We could fix it in two ways 🤔..
1. default values
2. dependency injection
Lets see them one-by-one. When we design a class we can define its stored variables with some default/initial values which will make sure that it will have some value before its accessed at any time, something like this..
This approach doesn’t change the way we create a new user..
let user = User()
..it will compile just fine and won’t cause any run-time error either!
But this technique is only recommended if it makes sense to have default values for them. Otherwise its just an easy escape from your problem and will lead to side effects with unknown behaviour 😟
Lets checkout our second solution, dependency injection. Its also a way of providing initial values for stored properties but it defers from our first approach in a way that in dependency injection we pass their initial values within the initialiser itself when we create an instance. This way we can have more control over its variables which looks something like this..
..now instead of relying on its class to have default values we make sure that we supply its value when we create its instance..
let user = User(firstName: "Ritesh", lastName: "Gupta")
This way feels way safer & in control now as you will know the exact values of its properties when creating its instance and there won’t be any side effects what so ever 😎
Of course sometimes its beneficial to have default values as well so its depend on your use case 👍
Now that we have talked about different ways of providing initial values, you may have silently noticed that I have used
var for declaring properties so lets talk about it and see if we can use compile-time errors here as well.
Swift has given us two ways to declare a variable —
letmakes property immutable, once initialised you can’t update its value later.
varmakes property mutable, you can update its value as you like, whenever you like.
So depending on your use case, if you know that its value shouldn’t change in future then you should make it
let, something like..
..this will tell the compiler to warn us again if we try to update
lastName later on in the code..
Again we have leveraged the compile-time error (😇 twin is happy) and made sure that we kept the design of our class clear & precise as per our use case! Also it will help & guide other developers to use it in a better and safe manner!
I hope you enjoyed this post and it made you think positive things about compile-time errors. Follow me to stay tuned with my following posts in this multi part blog series where I’ll unravel more such scenarios where compile-time errors are really helpful! 😊