76

I am trying to understand the use of the required keyword in Swift classes.

class SomeClass 
{
    required init() {
        // initializer implementation goes here
    }
}

required doesn't force me to implement the method in my child-class. If I want to override the required designated initializer of my parent class I need to write required and not override. I know how it works but can not understand why I should do this.

What is the benefit of required? As far as I can tell, languages like C# don't have something like this and work just fine with override.

pseudonym117
  • 799
  • 1
  • 5
  • 22
TalkingCode
  • 13,407
  • 27
  • 102
  • 147
  • Implementation in your subclasses is not required because of inheritance, which makes sense. However I am also wondering the benefit here. If a subclass (which hypothetically overrides `init()` but not some required initializer) gets init by a process that called the inherited required initializer, and that required initializer subsequently calls `init()`, wouldn't it call the subclass' overridden init and all is good? -- I would think the only good reason would be that the required initializer **does not** call `init()` on self, so overriding 'init()' would never be called. – Andrew Robinson May 06 '15 at 19:16
  • 1
    This might be interesting in this context: [Protocol func returning Self](http://stackoverflow.com/questions/25645090/protocol-func-returning-self). – Martin R May 06 '15 at 19:41

4 Answers4

118

It's actually just a way of satisfying the compiler to assure it that if this class were to have any subclasses, they would inherit or implement this same initializer. There is doubt on this point, because of the rule that if a subclass has a designated initializer of its own, no initializers from the superclass are inherited. Thus it is possible for a superclass to have an initializer and the subclass not to have it. required overcomes that possibility.

One situation where the compiler needs to be satisfied in this way involves protocols, and works like this:

protocol Flier {
    init()
}
class Bird: Flier {
    init() {} // compile error
}

The problem is that if Bird had a subclass, that subclass would have to implement or inherit init, and you have not guaranteed that. Marking Bird's init as required does guarantee it.

Alternatively, you could mark Bird as final, thus guaranteeing the converse, namely that it will never have a subclass.

Another situation is where you have a factory method that can make a class or its subclass by calling the same initializer:

class Dog {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class NoisyDog: Dog {

}

func dogMakerAndNamer(whattype: Dog.Type) -> Dog {
    let d = whattype.init(name: "Fido") // compile error
    return d
}

dogMakerAndNamer is calling the init(name:) initializer on Dog or a Dog subclass. But how can the compiler be sure that a subclass will have an init(name:) initializer? The required designation calms the compiler's fears.

Jari Keinänen
  • 1,361
  • 1
  • 21
  • 43
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • So if "NoisyDog" has 'let noise: String', what would you do in 'required init(name: String)'? Is the "right" way to change the var to 'var noise: String!' and hope that if someone inits using Dog.Type as above that they also somehow know to set the 'noise' var after? Or do you have to provide a default like 'var noise = "Arf!"' that some of your custom initializers replace? I'm looking for best practices here (this seems like a poorly thought-out language construct which breaks a lot of standard OO patterns, but I know the designers of Swift are better than that, so there must be a good way). – Tom Dibble Jun 09 '18 at 17:55
  • Alternatively, is "best practice" that 'required' should rarely, if ever, be used? – Tom Dibble Jun 09 '18 at 17:56
  • 2
    The only time you would ever say `required` is when forced to it by the compiler. The compiler will ding you and you'll use one of the solutions described above. Otherwise, don't use it. – matt Jun 09 '18 at 17:59
  • how in the first example the sub-class would not inherit the init() ? – Artiom Feb 06 '22 at 15:41
  • 1
    @ArtiomLemiasheuski If the subclass also declared an initializer. Sure it might not, but the compiler cannot know that in advance. – matt Feb 06 '22 at 16:00
  • thanks, that makes sense! – Artiom Feb 06 '22 at 17:01
  • I moved to Swift after 25 years of C++ and the "required" syntax fixes a problem that causes a LOT of subtle bugs in C++ – Andy Dent Feb 22 '22 at 04:51
12

According to the documentation:

Write the required modifier before the definition of a class initializer to
indicate that every subclass of the class must implement that initializer

So yes, required does force all child classes to implement this constructor. However, this is not needed

 if you can satisfy the requirement with an inherited initializer.

So if you have created more complex classes that cannot be fully initialized with a parent constructor, you must implement the require constructor.

Example from documentation (with some added stuff):

class SomeClass {
    required init() {
        // initializer implementation goes here
    }
}

class SomeSubclass: SomeClass {
    let thisNeedsToBeInitialized: String
    required init() {
        // subclass implementation of the required initializer goes here
        self.thisNeedsToBeInitialized = "default value"
    }
}
pseudonym117
  • 799
  • 1
  • 5
  • 22
10

I want to draw an attention on another solution provided by Required, apart from Matt has given above.

class superClass{
    var name: String
    required init(){
        // initializer implementation goes here
        self.name = "Untitled"
    }
}
class subClass: superClass {
    var neakName: String = "Subclass Untitled"

}
let instanceSubClass = subClass()
instanceSubClass.name        //output: "Untitled"
instanceSubClass.neakName    //output: "Subclass Untitled"

As you can check in above example, I've declared required init() on superClass, init() initializer of superClass has inherited by default on subClass, So you able to create an instance of subClass let instanceSubClass = subClass().

But, suppose you want to to add one designated initializer on subClass to assign run time value to stored property neakName. Of course you can add it, but that will result to no initializers from the superClass will be inherited to subClass, So if you will create an instance of subClass you will create through its own designated initializer as below.

class superClass{
    var name: String
    init(){
        // initializer implementation goes here
        self.name = "Untitled"
    }
}
class subClass: superClass {
    var neakName: String = "Subclass Untitled"
    init(neakName: String) {
        self.neakName = neakName
    }
}
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name       //output: "Untitled"
instanceSubClass.neakName   //output: "Bobby"

Here above, you won't be able to create an instance of subClass by just subClass(), But if you want that every subclasses of superClass must have their own init() initializer to create direct instance by subClass(). Just place required keyword before init() on superClass, it will force you to add init() initializer on subClass too - as below.

class superClass{
    var name: String
    required init(){
        // initializer implementation goes here
        self.name = "Untitled"
    }
}
class subClass: superClass {
    var neakName: String = "Subclass Untitled"
    init(neakName: String) {
        self.neakName = neakName
    }
}    // Compiler error <------------ required `init()` must be provided by subClass.
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name       //output: "Untitled"
instanceSubClass.neakName   //output: "Bobby"  

SO, use required keyword before initializer on superclass, when you want all subclasses must have been implemented required initializer of superclass.

Kiran Jasvanee
  • 6,362
  • 1
  • 36
  • 52
  • That doesn't make sense. Then, to fix that, you need to provide an init() on subclass, which leaves the subclass var unset. This leads to a lot of unmaintainable code, relying on var ...! and runtime errors if the 'required' init is ever used without coming back and cleaning up those 'will be initialized before use' vars, instead of let ... Requiring an init() to call super.init(withanyargs) handles this concern far far better. – Tom Dibble Jun 09 '18 at 17:47
0

If you are trying to add you own initialiser in the sub class, then you have to follow certain things those were declared in super class. So it make sure that you will not forget to implement that required method. If you forget compiler will give you error // fatal error, we've not included the required init() . Another reason is it creates a set of conditions that ever sub class should follow it the sub class is defining its own initialiser.

Amit89
  • 3,000
  • 1
  • 19
  • 27