Inherited convenience initializer - why does this work?

I have the following example and a question:
I know that initializer are inherited under some circumstances.

class Food{
    var name: String
    init(name: String) {
        self.name = name
    }
    
    convenience init() {
        self.init(name: "[unnamed]")
    }
}

class RecipeIngredient: Food {
    var quantity: Int
    
    init(name: String, quantity: Int){
        self.quantity = quantity
        super.init(name: name)
    }
    
    override convenience init(name: String){
        self.init(name: name, quantity: 1)
    }
}

let mystery = RecipeIngredient()  // Why does this work?

I would have expected that the initialization without any parameters doesn't work because the convenience initializer is only declared in the base class and doesn't set the quantity property.
Obviously it works anyway. But why? What happens in the background when I call the (at least in the child class not existing) initializer without any parameters?


Solution 1:

A sub class has the initialisers defined in it and the initialisers from the super class (unless of course any of them have are override in the sub class). So in this case there are 3 init for RecipeIngredient

From RecipeIngredient

init(name: String, quantity: Int){
    self.quantity = quantity
    super.init(name: name)
}

override convenience init(name: String){
    self.init(name: name, quantity: 1)
}

and one from Food

convenience init() {
    self.init(name: "[unnamed]")
}

Now a convenience init must call a default init, either directly or via another a convenience init so the chain of calls here becomes

Food.init() -> RecipeIngredient.init(name:) -> RecipeIngredient(name:quantity) -> Food.init(name:)

This can be easily seen by adding print(#function) to each init which gives the output for

let mystery = RecipeIngredient() 

init()
init(name:)
init(name:quantity:)
init(name:)