Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional generic type doesn't accept nil in method call

Tags:

swift

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:

  • protocol 'Event' can only be used as a generic constraint because it has Self or associated type requirements
  • V is passed to another generic collection that I control
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?

like image 998
Alessandro Vendruscolo Avatar asked Mar 14 '23 17:03

Alessandro Vendruscolo


1 Answers

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?)
}
like image 91
Sulthan Avatar answered Apr 02 '23 03:04

Sulthan