Default Value For Optional Generic Parameter in Swift Function

Default value for optional generic parameter in Swift function

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>

Swift Optional Generics Type required even though parameter is nil

Creating another overload is the way to do it. Swift doesn't have variadic generics yet. Until then, you'll need an overload for each number of placeholders. And zero is one of those numbers!

Typically, this means you'll be using a third (likely private) function for common functionality.

Note: it's impossible to use these default parameters, even though they compile!

private func common() { }

func ƒ() { common() }
ƒ()

func ƒ<T>(_: T? = nil) { common() }
ƒ( () )

func ƒ<T0, T1>(_: (T0, T1)? = nil) { common() }
ƒ(
( (), () )
)

Set default or nil value to the generic type parameter of the function

nil is too broad in this case, as the compiler can't infer to which [T]? it should apply the nil.

You will need to explicitly specify the Optional generic argument here:

self.genericCall(param: [StructOne]?.none)

Swift - Optional Generic Type

There's no such thing as an unused type. The type system needs to know the type of all variables and if you declare a generic type with 2 generic type parameters, both need to have a type.

Even if the value of u is nil at the time of init, it still needs a specific type, since Optional itself is a generic type, so you need to tell the compiler what Optional<U> is.

Moreover, unless you make u immutable, you cannot guarantee that it will never have a value just by not giving it a value in the init. (Actually you do give it a value, it just defaults to nil).

So the answer is NO, you cannot instantiate your GenericClass without specifying both T and U.

Default optional parameter in Swift function

Optionals and default parameters are two different things.

An Optional is a variable that can be nil, that's it.

Default parameters use a default value when you omit that parameter, this default value is specified like this: func test(param: Int = 0)

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(). Even though the parameter is optional, it doesn't have a default value.

You can also combine the two and have a parameter that takes an optional where nil is the default value, like this: func test(param: Int? = nil).

Is there no default(T) in Swift?

There isn't. Swift forces you to specify the default value, just like then you handle variables and fields. The only case where Swift has a concept of default value is for optional types, where it's nil (Optional.None).

Swift - Take Nil as Argument in Generic Function with Optional Argument

I believe you've overcomplicated the problem by requiring the ability to pass untyped nil (which doesn't really exist; even nil has a type). While the approach in your answer seems to work, it allows for the creation of ?? types due to Optional promotion. You often get lucky and that works, but I've seen it blow up in really frustrating ways and the wrong function is called. The problem is that String can be implicitly promoted to String? and String? can be implicitly promoted to String??. When ?? shows up implicitly, confusion almost always follows.

As MartinR points out, your approach is not very intuitive about which version gets called. UnsafePointer is also NilLiteralConvertible. So it's tricky to reason about which function will be called. "Tricky to reason about" makes it a likely source of confusing bugs.

The only time your problem exists is when you pass a literal nil. As @Valentin notes, if you pass a variable that happens to be nil, there is no issue; you don't need a special case. Why force the caller to pass an untyped nil? Just have the caller pass nothing.

I'm assuming that somethingGeneric does something actually interesting in the case that it is passed nil. If that's not the case; if the code you're showing is indicative of the real function (i.e. everything is wrapping in an if (input != nil) check), then this is a non-issue. Just don't call somethingGeneric(nil); it's a provable no-op. Just delete the line of code. But I'll assume there's some "other work."

func somethingGeneric<T>(input: T?) {
somethingGeneric() // Call the base form
if (input != nil) {
print(input!);
}
}

func somethingGeneric() {
// Things you do either way
}

somethingGeneric(input: "Hello, World!") // Hello, World!
somethingGeneric() // Nothing

Optional generic type doesn't accept nil in method call

Type inferring is not omniscient. When invoking a generic method, the compiler has to know the generic types you are using. Type inferring cannot see what type is nil supposed to be so you have to specify the types explicitly.

broadcastEvent(SettingsEvent.Baz, withValue: nil as NSString?)

Also note that String is a struct so it doesn't conform to AnyObject. Using a literal "aa" will make it a NSString.

I don't think you will be able to combine a generic type with a default parameter value of nil, only by defining a separate method

func broadcastEvent<E: Event>(event: E) {
broadcastEvent(event, withValue: nil as AnyObject?)
}


Related Topics



Leave a reply



Submit