Okay! Let’s get right at it! For all of us, iOS developers, there comes a time when we encounter Final in the code. At that time we ask ourselves what does it do? Where to use it? How to use it? When not to use it? And many other questions start popping up in our heads.
Here, I will try to answer these questions, and hopefully, decode the mystery of
final by the end.
Implications of using
- It prevents overriding and inheritance.
- It increases the runtime performance of the code.
But what does this mean??? Let’s see!
Prevent Inheritance and Overriding
Swift like most other object-oriented languages allows a class to inherit from another class and override methods and properties declared in its superclass.
However, this is not always desirable and ideal. There are many cases where we do not want anyone or any other part of the code to change the implementation of the class — such a class is to be used the way it is and any change is undesirable.
In such cases, declaring the class as
final will prevent it from being subclassed and thus, will prevent member overriding.
Similarly, there are cases when we do not want to change the implementations of a few members of the class. In that case, we do not want to override these few members. The way to do so is to declare them
Note — Please ignore edge case handling in User class member functions.
Enhance Runtime Performance
Saving time and avoiding any compiler computation at runtime makes one’s program efficient and fast. This is what makes
finalmore interesting and useful for any programmer like me.
Swift being an OOP language allows defining class and inheritance. This means there can be classes and subclasses and subclasses may/may not override properties and methods of the base class.
However, when we look at this from the system’s point of view, every time a class member is referred (no matter from the subclass or the base class), the system must perform the following computations at runtime —
- Check if the class is inherited anywhere in the code or is itself a subclass.
- Check if any of the class members are overridden and the number of times. And what possible implementations are available for the referenced member.
- Get the correct implementation out of the multiple overrides.
- Indirectly call the correct implementation from a pool of implementations.
These computations increase the expressivity of the language but add to the runtime overhead as they require more time and power per call. This decreases the overall efficiency of the code.
This entire chain of events of indirectly accessing the referenced member is termed as Dynamic Dispatch by Apple. But is it necessary to go through Dynamic Dispatch all the time — NO! The question that naturally arises then is how can one get rid of dynamic dispatch? How to write efficient code?
The answer is
final . When we declare a member
final, it not only specifies that it cannot be inherited/overridden but it also notifies the system that — Hey! No other similar entity exists. This ensures that the system need not worry and directly implement the one defined — and this happens at Compile time. Thus, removing the runtime overhead. This is called direct access or Static Dispatch — which happens at compile time.
This means by merely adding the word
final, we can shift the entire processing from runtime to compile time. Hence, increasing the runtime efficiency.
In the above snippet, when
User is instantiated, Dynamic dispatched calls are sent —
- to variables —
- to methods —
Also, in the above snippet, whenever
user is accessed, it is done via Dynamic dispatched calls.
Here, even though a single
User class exists, still Dynamic Dispatch is compulsorily used. This is because the system has no knowledge if a subclass of
User exists, or if any member is overridden anywhere. The system can gather this information either by looking up for them (which is dynamic dispatch) or if we explicitly notify it of their non-existence (which is handled by
So to sum it up — The above snippet shows a general use-case.
- Here the members are declared
finalto prevent overriding them.
- Declaring them
finaleliminates runtime overheads and implements a Static Dispatch.
This is all for now! Thank you for reading. Hope you found it informational.
Happy Coding 💻🖥
Here are some references to let you explore more about the topic —
- Apple blog — https://developer.apple.com/swift/blog/?id=27
- Different dispatches in Swift — https://heartbeat.fritz.ai/understanding-method-dispatch-in-swift-684801e718bc
- Swift documentation on
final— https://docs.swift.org/swift-book/LanguageGuide/Inheritance.html #Preventing Overrides.