Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protocol Extension Initializer forcing to call self.init

I was just reading the Apple Swift 4 document regarding the Protocol Initializer Requirements and providing a default implementation in the protocol extension.

import UIKit
protocol Protocol {
    init()
}
extension Protocol {
    init() {
        print("SDf")
        self.init() // Line 1
                    // Compiler error occured if this is omitted 
                    //"'self.init' isn't called on all paths before returning from initializer"
    }
}

struct Structure: Protocol {
    init(string: String) {

    }
}

Structure()      // Line 2

Now as you can see, the execution will go into a loop, as by default the structure doesn't have an implementation for init(), so the protocol provided init will be called and it will call itself again, and so it goes into an infinite loop.

Now, knowing this, if I remove Line 1, the compiler gives the error.

Q. Why is it forcing me to use self.init() on Line 1, and how can I get out of this situation?

like image 796
prat14k Avatar asked May 10 '18 09:05

prat14k


1 Answers

Consider this example:

protocol P {
  init()
}

extension P {
  init() {

  } // error: 'self.init' isn't called on all paths before returning from initializer
}

struct S : P {
  var str: String
}

let s = S()
print(s.str)

Suppose it compiled – we'd be able to create an S value without providing a value for the str property. That's why the compiler is complaining that your protocol extension implementation of init() isn't calling self.init. It needs you to chain to some other initialiser requirement – one that you don't provide a default implementation for (otherwise you could get into a recursive loop, as you found out), and therefore one that the adopting type needs to implement such that it can fully initialise itself.

For example, this is legal:

protocol P {
  init()
  init(str: String)
}

extension P {
  init() {
    self.init(str: "some default")
  }
}

struct S : P {
  var str: String
}

let s = S()
print(s.str) // some default

because now we're chaining to the init(str:) requirement, which S must implement (in this case it's satisfied by the implicit memberwise initialiser).

like image 104
Hamish Avatar answered Oct 20 '22 15:10

Hamish