Swift protocol with `default` parameter values

George Tsifrikas
2 min readJul 2, 2017

There is a very common case that you have a class which contains a method with default parameter values and you want to test it.

class Baz {
func foo(bar: BarType, camp: CampType = CampType()) -> String {
return "World"
}
}

You start by writing a protocol so you can implement a mock for your class, which looks like this:

protocol BazProtocol {
func foo(bar: BarType, camp: CampType) -> String
}

And the mock:

struct BazMock: BazProtocol {
func foo(bar: BarType, camp: CampType) -> String {
return ""
}
}

You want the mock to share the default values, so you start by setting the default values at the protocol definition and end up with something like this.

protocol BazProtocol {
func foo(bar: BarType, camp: CampType = "Hello") -> String
}

But you get the following error:

default argument not permitted in a protocol method

There is a way to get around of that restriction.

Extensions come to the rescue!

We won’t define default parameters at the Baz nor BazMock but we will use a protocol extension which will be the only place that the default values will be defined. That way both implementations of the same protocol have the same default values.

extension BazProtocol {
func foo(
bar: BarType,
camp: CampType = CampType()) -> String {
return foo(bar: bar, camp: camp)
}
}

What is happening here is that we call the protocol defined function foo inside our extension, which at runtime will invoke the correct method from our concrete types using the default values from the extension.

*Important note* Because protocol BazProtocol has already a default implementation from the extension if you use it in an object and forgot to implement function foo compiler won’t complaint, but extension function foo will call itself recursively until your code crashes with BAD_ACCESS.

Simple as that, we have protocol method definitions with default values.

Credits to Kostas Kremizas & Pavlos-Petros Tournaris for their feedback.

--

--