Swift Language Statically or Dynamically Dispatched

Swift language statically or dynamically dispatched?

Describing C++, Java, and C# as statically dispatched is not particularly accurate. All three languages can and often do use dynamic dispatch.

Swift, similarly, can do both. It does differ from ObjC in that it does not always dynamically dispatch. Methods marked @final can be statically dispatched, as can struct and enum methods. I believe non-final methods can be statically dispatched if the runtime type can be proven at compile time (similar to C++ devirtualization), but I'm not certain about the details there.

Is Swift a dynamic or static language?

It is static - very static. The compiler must have all information about all classes and functions at compile time. You can "extend" an existing class (with an extension), but even then you must define completely at compile time what that extension consists of.

Objective-C is dynamic, and since, in real life, you will probably be using Swift in the presence of Cocoa, you can use the Objective-C runtime to inject / swizzle methods in a Swift class that is exposed to Objective-C. You can do this even though you are speaking in the Swift language. But Swift itself is static, and in fact is explicitly designed in order to minimize or eliminate the use of Objective-C-type dynamism.

How do we determine a language is dynamic or static? an example is Swift

  1. I've never heard of the term "static language" or "dynamic language." The usual terms I've heard of are "statically typed language" or "dynamically typed language."

  2. "Dynamic" isn't a defined term in this context, so there's not much to say here.

  3. Polymorphism has multiple different meanings, so I'll assume you mean subtype polymorphism. In that case, yes, dynamic dispatch is necessary. The whole idea is that you want objects of different types to behave in their own way in response to the same message (method call). The only way to do this is to decouple messages and function invocations, so that an appropriate function can be called at runtime depending on the type of the receiver of the message.

  4. Swift is a statically typed language, through and through. This might be obscured a bit by type inference. If you have an expression like

     func someFunction() -> Int { return 123 }
    let x = someFunction()

    The type inference doesn't mean "x has some type that will be figured out at runtime." To the contrary, it means "The type of x can be deduced at runtime because we already know the type of someFunction."

    All types in Swift are known at compile time. In the worst case, a must at least have type Any, which is still a type. It's not a particularly useful type (because there isn't much an Any is guaranteed to be able to do), but it's still a type.

    There is some confusion in that there's talk of types at compile time and runtime types. Here's an example:

         class Car {
    func vroom() { print("vroom") }
    }

    class SportsCar: Car {
    override func vroom() { print("VROOOOOM") }
    }

    let car: Car = SportsCar()

    func driveSportsCar(_: SportsCar) { print("driving") }
    // Compile types are what determine usage compatibility
    driveSportsCar(car) // cannot convert value of type 'Car' to expected argument type 'SportsCar'

    // Runtime types are what determine method implementations
    car.vroom() // => "VROOOOOM"

    In this example, car has a compile time type of Car, and a runtime type of SportsCar. The compile time type determines how it can be used, where it can be passed, etc. For example, you couldn't pass car to a driveSportsCar() function, because even though its runtime type is SportsCar, its compile time type is Car, which isn't compatible.

    The runtime type of an object is what determines the method implementations to be called.

Dynamic/runtime dispatch in Swift, or the strange way structs behave in one man's opinion

In your first example you're overriding the description property. This implementation is therefore added to OddString's vtable (as it's a class), and can be dynamically dispatched to just fine, regardless of what the instance is statically typed as.

In your second example, you don't have a class – so no vtables. However you are conforming to a protocol. Protocols allow for dynamic dispatch via protocol witness tables (see this great WWDC talk on them), however this only happens for implementations of protocol requirements.

localizedDescription isn't a protocol requirement of the Error protocol, it's merely defined in a protocol extension of Error when you import Foundation (this is documented in SE-0112). Therefore it cannot be dynamically dispatched. Instead, it will be statically dispatched – so the implementation called is dependant on the static type of the instance.

That's the behaviour you're seeing here – when your explosive instance is typed as TestError, your implementation of localizedDescription is called. When typed as Error, the implementation in the Error extension is called (which just does a bridge to NSError and gets its localizedDescription).

If you want to provide a localised description, then you should conform your error type to LocalizedError instead, which defines errorDescription as a protocol requirement – thus allowing for dynamically dispatch. See this Q&A for an example of how to go about this.

Swift which method dispatch is used?

This method can be statically dispatched, because aaaa has one fixed, statically-known type (AAA).

If you instead had something like anyBBBB: any BBBB = aaa, then calling anyBBBB.printSome() would need dynamic dispatch, because it's not known which concrete type is involved until runtime. (Of course, if the compiler's data-flow analysis can prove there's only one possible type in that spot, then it can switch back to static dispatch. This is called Devirtualization)

Are public swift functions on ObjC objects dynamically or statically dispatched?

The Swift compiler will try to prove that a call to a method can only end up with a single implementation. If it can prove this then it will use static and not dynamic dispatch. Use of the "final" or "private" keyword, and whole module optimisation, will help with this.

why static dispatch so quickly in swift

You are confusing two separate concepts.

Static dispatch refers to the way a method body is called at runtime. If you have a class that could potentially have subclasses or any object where all you know about it is that it conforms to a certain protocol, you have to use dynamic dispatch, which means you have to look up the address of the method in a table (called a vtable or a witness table) and then jump to that location. If the compiler knows exactly what kind of object it has, e.g. a struct, a final class or a final method in a class, it knows the method cannot be overridden and can therefore directly jump to its address without doing the lookup.

A method that is declared static is a type method. It will be called on the type itself rather than an instance of the type i.e. inside the method self refers to the type not an instance of the type.

static methods can't be overridden so the compiler always knows the address at compile time and will use static dispatch for them. There's no need for any kind of hash table or witness table.

What is the difference between static func and final class func in swift

Just because a final class function can't be overridden doesn't mean it's statically dispatched. A final class function be override a superclass non-final class function. Such a method call must be dynamically dispatched.

static is merely an alias for final class. They behave the same:

class C1 { class func foo() {} }
class C2: C1 { override final class func foo() {} }
class C3: C1 { override static func foo() {} }


Related Topics



Leave a reply



Submit