Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generics as parameters to a closure in swift

Tags:

swift

I'm having trouble writing the following function as a closure

func myfunc<S where S: MyProtocol, S: MySuperClass>(param: S) { ... }

I tried

let myClosure = {<S where S: MyProtocol, S: MySuperClass>(param: S) in ... }

but it doesn't work.

Any suggestions?

like image 308
Erik Johansson Avatar asked Aug 20 '14 09:08

Erik Johansson


1 Answers

I believe what you're asking for can't make sense (having nothing to do with Swift). While I'm interested in being proven wrong, I don't believe this could be reasonably created in any strongly typed language. (EDIT: continuing my research, I believe this would be possible in a language with first-class polymorphism, but I am not aware of any general-use languages that actually have this feature.)

let myClosure = {<S where S: MyProtocol, S: MySuperClass>(param: S) in ... }

What type would you expect myClosure to be? A generic creates an abstract type. It does not become a real type until it is specialized. So myClosure would be of an abstract type itself. That's like asking for an instance of an abstract class. The whole point of "abstract" is you can't construct one. The best you could say would be that myClosure would itself be a type that you would need to instantiate into a real instance (but then let doesn't make any sense; you don't let types).

When you wrap this in a struct, what you're really doing is creating an abstract type that you will specialize into a real type when you create an instance.

Now what would make sense IMO (but appears currently to be impossible), is this:

typealias Mapping<S> = S -> S
let identity: Mapping<Int> = { return $0 }

That makes sense because you're defining an abstract type (Mapping), but then instantiating a concrete type Mapping<Int>. Unfortunately, typealias does not appear to support generics at this point, so a struct is probably the best tool we have.


Note that while typealias is a bust, it is clearly possible to specialize function variables themselves. This isn't a closure, I know, but may be useful in some of the same situations.

func Identity<T>(i:T) -> T {
  return i
}

let identityInt:(Int -> Int) = Identity
identityInt(1) // => 1

Using this to explore the problem of abstract types a little more, consider:

func Identity<T>(i:T) -> T { return i }
let x = Identity

This fails to compile with the error:

error: cannot convert the expression's type '(T) -> T' to type '(T) -> T'

That's because the type (T) -> T is not a concrete type, so you can't have one called x. Compare that to identityInt, which I explicitly specialized into a concrete type, and then could construct.

like image 65
Rob Napier Avatar answered Sep 20 '22 08:09

Rob Napier