Swift Tips and Tricks Part – 2: Dynamic Dispatch

Let me present to you some nuances of Swift! In this series of Tips and Tricks, I’ll touch upon topics which are generally overlooked but either are important or nifty.

One of such topics is Dynamic Dispatch.

Let look into hows and whats of the afore-mentioned!

Dynamic Dispatch

In Swift one is allowed to override methods and properties in a class declared in its superclass. This means that the program needs to determine at runtime which method or property is being referred too. Depending on which the program decides whether to make an indirect call or an indirect access! This behavior of a program is called Dynamic Dispatch i.e. deciding on run-time which method or property is being referred too.

You might ask, Hey Anirudh! It’s good, but what to do about it?

So you see Dynamic Dispatch adds up a bit of a runtime overhead. So in the programs/applications/code which is performance/time sensitive, dynamic dispatch becomes undesirable.

We’ll discuss three ways under static dispatch to eliminate such dynamism.

First up, using the  final keyword. Consider the following example:

The compiler will make a dynamically dispatched call to:

  1. Call update on smallCylinder.
  2. Call updateValues on smallCylinder.
  3. Get the property radius of smallCylinder.
  4. Get the property height of smallCylinder.
  5. Call volume on smallCylinder.
  6. Get the property radius of smallCylinder.
  7. Get the property height of smallCylinder.

This might not be what you would expect when looking at this code because direct calls seem to be the way ahead. The dynamic calls are necessary because a subclass of CylinderModel might override radius or height with a computed property or override updateValues() or update() with new implementations.

In Swift, dynamic dispatch calls are implemented by looking up a function from a method table and then performing an indirect call. This is slower than performing a direct call. Additionally, indirect calls also prevent many compiler optimizations, making the indirect call even more expensive. In performance critical code there are techniques you can use to restrict this dynamic behavior when it isn’t needed to improve performance. Let’s discuss them in detail.

What role can  final play here?

Use  final when the declaration does not need to be overridden. Adding  final keyword enforces a restriction on property, class or a method, that the item in question cannot be overridden. Take a look at the updated code,

 

Adding the final keyword to both the properties and the methods updateValues and volume makes the compiler to safely ignore the dynamic dispatch. Hence the properties and methods which are final are called or referenced to directly, improving the performance.

You may ask, why can’t I make the entire class as final, to which I’d say, be my guest. Making the class inherently makes the functions and properties can’t be overridden.

Second, you may make use of private keyword. Now how does this help? Let me explain.

Applying the  private keyword to a declaration restricts its visibility to the current file. This allows the compiler to find all potentially overriding declarations. The absence of any such overriding declarations enables the compiler to infer the  final keyword automatically and remove indirect calls for methods and property accesses.

Consider this,

Assuming there is no class overriding CylinderModel in the current file, the compiler can replace all dynamically dispatched calls to private declarations with direct calls.

Similarly, the class can also be made private, but that depends on the design and the architecture of the program/application you are working on.

The third is *drumroll* enabling Whole Module Optimisation!

Declarations, when done with internal access, are only visible within the module where they are declared. This is the reverse of using the internal or private that we saw above. If Whole Module Optimization is enabled, all of the modules are compiled together at the same time. This allows the compiler to make inferences about the entire module together and infer final on declarations with internal if there are no visible overrides. Consider the following,

What happens here is, that the compiler can infer final on the properties and methods update and volumeOnly the method update does not have public access, hence the compiler won’t infer it as final.

I hope this nifty trick helps you in optimizing the performance of your code/program/application. Do let me know how did you like it in the comments below. Adios!

Peace ✌

Please follow and like us:

Leave a Reply

Your email address will not be published. Required fields are marked *