gujci
gujci

Reputation: 1284

swift closure cannot override Any

Maybe it's a stupid question, but I couldn't find any solutions yet. So, my problem is, that is have an event emitter protocol with a function like this:

mutating func on(eventName:String, action:((Any?)->())) {
    //..
}

And I want to use it to inform the listeners whenever an event is triggered with some information. Access token for the "login" event for example.

appSessionHadler.on("login") { (weak data: String?) in
    //...
}

And than I get an error, that I cannot invoke "on" with that argument list of type. Of course it works with Any:

appSessionHadler.on("login") { (weak data: Any?) in
    //...
}

Everything conforms to Any, so I'm a but confused. Can someone explain this, please!

I could solve this with a Generic protocol, but it still frustrates me that it does not works like this.

Upvotes: 3

Views: 730

Answers (1)

Rob Napier
Rob Napier

Reputation: 299455

You're making a promise the compiler can't keep. The on function is free to call action with any kind of data at all. But the function you passed only accepts String. What is the system supposed to do if on includes the following code (directly or indirectly):

action(1)

1 is not a String, so type safety would be broken. The compiler can't let you do that.

Another way to think about this is that on takes a function of type F, and you are passing a supertype of F rather than a subtype of F. String is a subtype of Any. But function parameters work in the reverse order. (String)->Void is a supertype of (Any)->Void. So this is the same as passing a variable of type Any to a function that requires String. Formally we say that functions are contravariant in their parameters and covariant in their return values. You can read more on that in Type Variance in Swift.

As you suspect, generics are the right answer here. Any is almost always the wrong tool. And Any? is one of the hardest types to work with in Swift, so I'd definitely avoid that one at all costs. (Optional is itself a subtype of Any, and Swift has automatic promotion to Optional, so it is very common when you have Any? to start getting double Optionals and worse.)

Upvotes: 2

Related Questions