Ambiguous convenience initializers

I was just setting up a class with a designated initializer and a convenience initializer to be able to pass in initializing properties beyond the defaults:

[sourcecode language=”javascript”]
class Font {
var name = "Arial"
var size = 12
init() {

}
convenience init(name:String,size:Int) {
self.init()
self.name = name
self.size = size
}
}
[/sourcecode]

Great, all good so far. But sometimes a Font will be instantiated with a different name, but we want to leave the size as the default(or vice versa). Let’s add a default value to the name and size parameters in the convenience initializer:

[sourcecode language=”javascript”]
convenience init(name:String="Arial",size:Int=12) {
[/sourcecode]

Oh. You’ll see the obscure error on `self.init()`:
> Could not find an overload for ‘init’ that accepts the supplied arguments

What’s going on here? The error message isn’t very clear. If you comment out the offending line in the convenience initializer, and try to instantiate the class, you get a better idea of the problem:

Screenshot 2015-08-03 10.38.06

Two initializers without parameters appear for the Font class. How does the compiler know which initializer you intend it to run with the following line?

[sourcecode language=”javascript”]
var font = Font()
[/sourcecode]

If you instantiate Font without parameters, you’ll see the error:
> Cannot invoke initializer for type ‘Font’ with no arguments”.

Still not a very clear error message, but you’ll probably be starting to get the idea why. You’ll see a much clearer error message if you set up two functions with the same name, one with a parameter with a default value:

[sourcecode language=”javascript”]
class Planet {
var name = "World"
func greet()->String {
return "Hello \(name)"
}

func greet(name:String = "World")->String {
self.name = name
return "Hello \(name)"
}
}
var planet = Planet()
planet.greet()
[/sourcecode]

This time, you’ll see the error message:
> Ambiguous use of ‘greet’

Short and sweet, but I think it gets the point across much more clearly – ambiguity is the issue!

So stepping back a second – what’s a convenience initializer for? Supporting the designating initializer. But is a convenience initializer necessary if all of the parameters have default values? No!

[sourcecode language=”javascript”]
class Font {
var name = "Arial"
var size = 12

init(name:String="Arial",size:Int=12) {
self.name = name
self.size = size
}
}
var arial = Font()
arial.name
arial.size

var comicSans = Font(name: "ComicSans", size: 10)
comicSans.name
comicSans.size

var times = Font(name: "Times")
times.name
times.size

var bigArial = Font(size: 48)
bigArial.name
bigArial.size
[/sourcecode]

Unknown's avatar

iOS development with Swift - book: https://manning.com/books/ios-development-with-swift video course: https://www.manning.com/livevideo/ios-development-with-swift-lv

Tagged with: ,
Posted in Swift

Leave a Reply

Discover more from Before I forget...

Subscribe now to keep reading and get access to the full archive.

Continue reading