Alessandro Vendruscolo
Alessandro Vendruscolo

Reputation: 14877

Optional generic type doesn't accept nil in method call

Using the typed Enum feature of Swift 2 I can define some events that can be broadcasted and listened by my app. Doing so I can have the compiler check things for me and also I don't have to provide strings.

protocol Event: RawRepresentable {}

// Somewhere in a view
enum SettingsEvent: String, Event {
    case Bar
    case Baz
}

// Somewhere else in the app
enum ViewEvents: String, Event {
    case Foo
    case Bar
}

Events can be broadcasted, and this is the function that performs that. I need to use two generic types because:

func broadcastEvent<E: Event, V: AnyObject>(event: E, withValue value: V? = nil) {
    // Do something with event and value. This is not the real function body
    print(event.rawValue)
    if let v = value {
        print(v)
    }
}

Now, this call works:

broadcastEvent(SettingsEvent.Baz, withValue: "aa")

While these don't work

broadcastEvent(SettingsEvent.Baz)
broadcastEvent(SettingsEvent.Baz, withValue: nil)

The compiler says:

error: cannot invoke 'broadcastEvent' with an argument list of type '(SettingsEvent, withValue: NilLiteralConvertible)'

note: expected an argument list of type '(E, withValue: V?)'

What's wrong with this?

Upvotes: 4

Views: 4119

Answers (2)

Sulthan
Sulthan

Reputation: 130102

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?)
}

Upvotes: 7

Yannick Loriot
Yannick Loriot

Reputation: 7136

This is because by defining AnyObject as generic you are using the AnyObject protocol (not the object). The protocol does not conform to the NilLiteralConvertible one and so it does not recognize the nil literal.

In your case you should define your method like that:

func broadcastEvent<E: Event>(event: E, withValue value: AnyObject? = nil)

Upvotes: 0

Related Questions