How would you answer this typical iOS interview question? 🤨

Hi đź‘‹

This is going to be a very busy week for me!

Today I’m heading to Warsaw for the plSwift conference, where I’ll be talking about the lessons I’ve learned while using SwiftUI in the context of an existing UIKit app.

After months of focusing on short high-impact YouTube content, preparing for a 40-minute talk felt very weird, wish me luck!

But that’s not all, because I also have a very exciting livestream scheduled for Thursday evening: we’re going to talk about iOS career advice and how to grow professionally as an iOS developer!

And this is where I need your input: if you have any questions on that topic that you would like me to try and answer during the live, please share them with me!

(you can share them just by replying to this email đź‘Ś)


“What’s the difference between method overload and method override?”

How would you answer this typical iOS interview question? 🤨

Here's the answer I would suggest!

It’s always good to start by contextualizing the question.

It's no coincidence that “overload” and “override” feel confusingly similar!

It's because both concepts refer to a different flavor of polymorphism.

And polymorphism is about how a same symbol can represent multiple different things, depending on the context in which it is used.

So let's see which kind of polymorphism do “overloading” and “overriding” implement!

Let's start with “overloading”.

We overload a method when we define one or more methods with the same name, but with a different combination of arguments.

In Swift, overloading can happen in two different ways.

It can happen either by explicitly defining a new implementation of a method for each combination of arguments, like here:

func handle(value: Int) { 
    /* ... */
}

func handle(value: Double) {
    /* ... */
}

The compiler will then take care of calling the correct method, depending on the type of the argument used at the call site đź‘Ś

But overloading can also be achieved by using a generic argument (also known as parametrized type).

In that case, the compiler will take care of creating overloads that match each call site.

func handle<T: Numeric>(value: T) { 
    /* ... */
}

It's important to note that this form of polymorphism doesn't depend on runtime conditions, and so can be entirely handled at compile time.

This is important because it means that the compiler is able to optimize the code so that there's little-to-no overhead at runtime.

Now let's talk of “overriding”!

Once again, the idea is for a same method to have a different behavior, depending on the context in which it is called.

But this time the behavior won't depend on the arguments passed to the method but rather on the actual type of the object the method is called upon.

In Swift, method overriding is only possible when using classes.

Here's how it typically looks like:

class A {
    func method() { 
        print("class A implementation") 
    }
}

class B: A { 
    override func method() { 
        print("class B implementation") 
    }
}

When we call the method, the implementation that will be used will depend on the actual type of the instance at runtime.

let instance: A = B()

instance.method() // "class B implementation"

Unlike overloading, overriding does have a cost at runtime, because the compiler won't be able to prematurely decide on the right method to call, since it can depend on state that won't be known until runtime:

let instance = Bool.random() ? A() : B()

instance.method()

So to sum it up:

- overloading is about providing different method implementations depending on the argument types used at compile time

- overriding is about the same thing, but this time depending on the instance type used at runtime

Once you've answered the question, it's always nice to also quickly mention any extra knowledge you might have about the topic!

Here you could mention that, because Swift supports sub-typing, it's totally possible for a call site to have more than one potential method overload candidate that matches the types being used.

In order to decide which candidate overload should be used, Swift relies on a set of rules.

For instance, Swift will always prefer an overload with a matching concrete type over one with a matching generic type.

Here's how such a situation would look like:

func handle(value: Int) { 
    print("non-generic overload")
}

func handle<T: Numeric>(value: T) { 
    print("generic overload")
}

let int: Int = 3

// calls the non-generic overload
handle(value: int)

We can stop here, I think we’ve delivered a pretty solid answer ✌️

If you’re curious to see more examples of how to answer typical iOS interview question, I actually recorded an entire course on the topic!

That’s all for this email, thanks for reading it!

If you’ve enjoyed it, feel free to forward it
to your friends and colleagues 🙌

I wish you an amazing week!

❤️

Previous
Previous

There are so many cool new features in Swift and Xcode 🤩

Next
Next

3 tips to write better Swift code