Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default value for optional generic parameter in Swift function

Tags:

generics

swift

Is it possible to give an optional generic parameter a default value?

I'm trying to do something like this:

func addChannel<T>(name: String, data: T? = nil) -> Channel {

}

let myChannel = addChannel("myChannelName")

But I'm getting an error saying

Argument for generic parameter 'T' could not be inferred

Is it just a case of what I'm trying to do being impossible?

like image 915
hamchapman Avatar asked Feb 11 '15 15:02

hamchapman


People also ask

Is it possible to give a default value to a function parameter Swift?

In Swift, we can provide default values to function parameters.

How do you pass an optional parameter in Swift?

An Optional is a variable that can be nil , that's it. If you specify a parameter that is an optional, you have to provide it, even if the value you want to pass is nil . If your function looks like this func test(param: Int?) , you can't call it like this test() .

How do I make generic optional?

To make a generic type optional, you have to assign the void as the default value. In the example below, even though the function takes a generic type T, still you can call this function without passing the generic type and it takes void as default.

What is generic function in Swift?

Swift Generics allows us to create a single function and class (or any other types) that can be used with different data types. This helps us to reuse our code.


3 Answers

It's impossible in the way you've done it. Given just the code above, what type is T? The compiler, as it says, can't figure it out (neither can I, and I assume you couldn't either because the data's not there).

The solution to the specific question is to overload rather than use defaults:

func addChannel<T>(name: String, data: T?) -> Channel { ... }

func addChannel(name: String) -> Channel { ... }

let myChannel = addChannel("myChannelName")

But it raises the question of what you're doing here. You would think that Channel should be Channel<T>. Otherwise, what are you doing with data? Without resorting to Any (which you should strongly avoid), it's hard to see how your function can do anything but ignore data.

With Channel<T> you can just use a default, but you'd have to provide the type:

func addChannel<T>(name: String, data: T? = nil) -> Channel<T> { ... }
let myChannel: Channel<Int> = addChannel("myChannelName")

Otherwise the compiler wouldn't know what kind of channel you're making.

(UPDATE ~ Swift 5.2)

Sometimes you'd like a default type for T. You can do that with an overload. For example, you might want the default type to be Never. In that case, you would add an overload like this:

func addChannel<T>(name: String, data: T? = nil) -> Channel<T> { ... }
func addChannel(name: String) -> Channel<Never> { 
    addChannel(name: name, data: Optional<Never>.none)
}

With that, you can have a simpler call:

let myChannel = addChannel(name: "myChannelName") // Channel<Never>
like image 188
Rob Napier Avatar answered Nov 07 '22 07:11

Rob Napier


I ran into the same problem. While not being able to use the generic default traditionally — leaving the argument out completely — I prefer the below to implementing overloads:

let myChannel=addChannel("myChannelName", data: Optional<Any>.none)
like image 43
shoe Avatar answered Nov 07 '22 06:11

shoe


I use a combination of the existing answers so that I can both call the function without the optional argument and avoid implementing the function twice.

func addChannel(name: String) -> Channel {
    addChannel(name: name, data: Optional<Any>.nil)
}
func addChannel<T>(name: String, data: T? = nil) -> Channel {
    ...
}

As mentioned above you should avoid Any. In my case I know that T is an Encodable so I use this:

struct DefaultEncodable: Encodable {}

func function1(name: String) {
    addChannel(name: name, data: Optional<DefaultEncodable>.nil)
}
func function1<T: Encodable>(name: String, data: T? = nil) {
    ...
}

like image 33
respectTheCode Avatar answered Nov 07 '22 07:11

respectTheCode