Type understanding

The missing part of your understanding is that this is not considered to be an implementation of the protocol requirement render(), because this method takes a single argument—its name is render(separator:)—and the protocol requirement takes none.

Therefore, your class relies on the default implementation of render() to fulfill its protocol requirement. You can see that this is the case just by playing with the concrete type:

let r: () -> String = A().render
r() // prints "[Renderable]"

To address this issue, you can declare public func render() -> String on your class and call the other method (you'll need to provide the default argument explicitly).


The following fact may help to refine your understanding of how Swift handles default arguments—

Given the following function f in library A and a user that calls the function in app B:

// library A
public func f(x: Int = 42) { ... }
// app B
f()

A lot of folks mistakenly think that this would compile as though it were written like this:

// library A
public func f(x: Int) { ... }
public func f() { f(x: 42) }
// app B
f()

Not so. In fact, it compiles as though it were written like this:

// library A
public func f(x: Int) { ... }
// app B
f(x: 42)

In other words, the default value is emitted into the caller (here, app B).

You can observe this difference on platforms where libraries can be distributed separately from the apps that call them. In that case, a future version of library A can change the default argument from 42 to 21 without breaking the functionality of an already compiled app B.

10 Likes