Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Protocol Inheritance & Generic functions

Consider the following playground:

import Foundation

protocol StringInitable {
    init( string:String )
}

class A : StringInitable {
    var stored:String

    required init ( string:String ) {
        stored = string
    }
}

class B : A /*, StringInitable */ {
    var another_stored:String

    required init ( string:String ) {
        another_stored = "B-store"

        super.init(string: string)
    }
}

func maker<T:StringInitable>(string:String) -> T {
    return T(string: string)
}

let instanceA = A(string: "test-maker-A")
let instanceB = B(string: "test-maker-B")

let makerA:A = maker("test-maker-A")
let makerB:B = maker("test-maker-B")

let typeInstanceA = _stdlib_getTypeName(instanceA)
let typeMakerA = _stdlib_getTypeName(makerA)

let typeInstanceB = _stdlib_getTypeName(instanceB)
let typeMakerB = _stdlib_getTypeName(makerB)

From the results the compiler seems to have inferred the correct types but has failed to call the correct initializers. How come I have to explicitly implement StringInitable in the B-class (test by removing the comment in the B class definition) to have the generic function "maker" call the correct initializer?

like image 685
Måns Severin Avatar asked Oct 06 '14 16:10

Måns Severin


People also ask

What is protocol inheritance in Swift?

One protocol can inherit from another in a process known as protocol inheritance. Unlike with classes, you can inherit from multiple protocols at the same time before you add your own customizations on top. Now we can make new types conform to that single protocol rather than each of the three individual ones.

How does Swift handle multiple inheritance?

Swift doesn't allow us to declare a class with multiple base classes or superclasses, so there is no support for multiple inheritance of classes. A subclass can inherit just from one class. However, a class can conform to one or more protocols.

Can Swift protocol have properties?

A protocol can have properties as well as methods that a class, enum or struct conforming to this protocol can implement. A protocol declaration only specifies the required property name and type.


1 Answers

That smells like a compiler bug for one simple reason: makerB is a variable of B type, but it is assigned an instance of A. This should not be possible, and in fact if you try to print, and more generally to access to, the another_stored property of the makerB variable, a runtime exception is raised, and I wouldn't expecting nothing else.

That's because if B is a subclass of A, an instance of A cannot be assigned to a variable of B type (whereas the opposite is possible).

Assigning a variable of A type to a variable of B type is possible though, but only under these conditions:

  • an explicit downcast from A to B is done (the compiler should error otherwise)
  • the instance referenced by the A variable is actually an instance of B (a runtime exception should be raised otherwise)

Note that the compiler didn't just fail to call the correct initializer - it called the initializer of another class

like image 56
Antonio Avatar answered Nov 11 '22 07:11

Antonio