David Moles
David Moles

Reputation: 51153

How do I call a generic Swift function when none of the arguments provides the generic type?

The following compiles in the Swift REPL:

var m: [String:AnyObject] = [:]
func f<T: AnyObject>(s: String) {
    m[s] = T.self
}

However, if I naively try to invoke f(), thus:

let s: String = "foo"
class Foo {}
f<Foo>(s)

I get this error:

repl.swift:7:1: error: cannot explicitly specialize a generic function
f<Foo>(s)
^
repl.swift:7:2: note: while parsing this '<' as a type parameter bracket
f<Foo>(s)
 ^

If I try it without "explicitly specializing"...

f(s)

Swift decides I'm trying to do something even weirder, and I get:

repl.swift:7:1: error: cannot convert the expression's type 'String' to type '()'
f(s)
^~~~

Meanwhile, however, if I define a new function g() as follows:

func g<T: AnyObject>(s: String, t: T) {
    m[s] = T.self
}

and pass in a dummy Foo instance:

g(s, Foo())

it works fine:

> m
$R0: [String : AnyObject] = {
  [0] = {
    key = "foo"
    value = {
      instance_type = {}
    }
  }
}

So is there a reason Swift lets me define f() in the first place? And once defined, is there any way to invoke it?


ETA: I'm aware it's also possible to define a function h<T: AnyObject>(s: String, t: T.Type) that takes the type explicitly. It's the fact that Swift allows me to define the implicit version that I find questionable.

Upvotes: 4

Views: 1400

Answers (1)

Antonio
Antonio

Reputation: 72760

Differently from other languages, you cannot explicitly specify the generic type with a syntax like this:

f<Foo>(s)

instead the actual type is inferred via a parameter or the return type. In your case you are not providing a way for type inference to figure out what T is. And sadly I'm not aware of any way to use that function.

My suggestion is to explicitly pass the type of T:

func f<T: AnyObject>(s: String, type: T.Type) {
    m[s] = type
}

...

f(s, Foo.self)

Upvotes: 4

Related Questions