Compile Time Errors Are Good

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. 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!


Introduction

Lets see an example to understand what I mean..

Objective — We have to create an User class which has two properties, firstName & lastName. The naive way of designing it would be..


class User {	
	var firstName: String!
	var lastName: String!
	
	init() {
	}
}

..and to create a new user object we could simply write..

Get more development news like this


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 firstName & lastName and for some reason the compiler couldn’t warn us either. Let’s see what’s going on and try to refactor it..

We could start by throwing away the unnecessary ! (bang operator). Wait.. why is it 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.

And 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

Let’s 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.


class User {	
	var firstName: String = "Ritesh"
	var lastName: String = "Gupta"
	
	init() {
	}
}

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 it’s just an easy escape from your problem and will lead to side effects with unknown behaviour.

Let’s checkout our second solution, dependency injection. It’s 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.


class User {	
	var firstName: String
	var lastName: String
	
	init(firstName: String, lastName: String) {
		self.firstName = firstName
		self.lastName = lastName
	}
}

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 let’s 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 — let & var.


    let makes property immutable, once initialised you can’t update its value later.
    
    var makes 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.


class User {
	
	let firstName: String
	let lastName: String
	
	init(firstName: String, lastName: String) {
		self.firstName = firstName
		self.lastName = lastName
	}
}

This will tell the compiler to warn us again if we try to update firstName or 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!

Conclusion

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! 😊

Next Up: New Features in Realm Obj-C & Swift

General link arrow white

About the content

This content has been published here with the express permission of the author.


Ritesh Gupta

Ritesh Gupta is an iOS Developer at Fueled. He has been working with Swift for 2 years and in iOS for almost 4 years. He loves protocol oriented programming & wants to convert the entire UI Kit with protocols. He shares his swifty thoughts on medium at - https://medium.com/@_riteshhh & runs Swift-Snippets publication - https://medium.com/swift-snippets. He is also an organiser at Swift India, community for Swift developers in India. He also spends some time in open source contribution, writing reusable components in Swift - https://github.com/riteshhgupta?tab=repositories

4 design patterns for a RESTless mobile integration »

close