Search code examples
swiftperformancefinaldispatchmethod-dispatch

Does marking a Swift class final also make all contained vars, lets and functions gain Static Dispatch benefits automatically?


I am trying to squeeze every last bit of performance out of my app. I try to use Structs over classes wherever possible (no state sharing, direct dispatch by default, etc etc). But my view controllers and UIView objects are obviously still classes. I want to force direct dispatch on every single one of my methods and data members - for performance reasons.

Do I need to still mark every var, let and func in my class final, or is it enough to just mark the hosting class final, in order for everything underneath it to take advantage of direct method dispatch?

In other words: It's very tedious to paste final everywhere - before each method and variable. So I'm hoping that just putting it on the class itself has the same effect of forcing direct dispatch on all class members. But I don't know how to test or verify it.

For those who are wondering what I'm talking about, check out this article: "Method Dispatch in Swift". Structs and protocol extensions give you Static Method Dispatch by default (fastest performance), but classes do not. Static methods in classes do, but I want to force Static Dispatch on all instance methods and data members.
https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/

The swift language runtime documentation mentions the effect on ability to subclass, but does not describe what happens to the dispatch behavior of child members and functions of classes that are marked "final". It would be nice if everything underneath gained Static Method Dispatch without having to mark everything final individually.

final

Apply this modifier to a class or to a property, method, or subscript member of a class. It’s applied to a class to indicate that the class can’t be subclassed. It’s applied to a property, method, or subscript of a class to indicate that a class member can’t be overridden in any subclass. For an example of how to use the final attribute, see Preventing Overrides.


Solution

  • Yes, just mark the type as final and its properties and methods are final, too. But if this is UIKit code (method overrides, UIKit delegate methods, etc.), that’s always going to be dispatched dynamically. It’s really only material for your own, computationally intensive code, and even then there’s a question as to whether that’s the critical issue or whether there are other issues (e.g. lookups in arrays rather than dictionaries, parallelization of complex routines, use of Accelerate or Metal of certain tasks, turning on optimized release builds, etc.).

    But if you’re converting to static dispatch on code that isn’t called very frequently, the difference may be modest/unobservable.

    We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.

    I’m curious if you’ve really done enough analysis to confirm you’re in that 3%. If you have, I apologize for pointing out the obvious; it’s just that I didn’t see anything above to indicate how you determined that static dispatch was going to make a real difference. If you have a performance issue, usually going through and making everything final is unlikely to be the silver bullet to resolve the issue.


    I’d refer you to WWDC videos that outline methodologies for identifying and resolve practical performance issues: