Cannot explicitly specialize a generic function

I have issue with following code:

func generic1<T>(name : String){
}

func generic2<T>(name : String){
     generic1<T>(name)
}

the generic1(name) result to compiler error "Cannot explicitly specialize a generic function"

Is any way to avoid this error? I can't change signature of generic1 function, therefore it should be (String) -> Void


I also had this problem and I found a workaround for my case.

In this article the author has the same problem

https://www.iphonelife.com/blog/31369/swift-programming-101-generics-practical-guide

So the problem seems to be, that the compiler needs to infer the type of T somehow. But it isn't allowed to simply use generic< type >(params...).

Normally, the compiler can look for the type of T, by scanning the parameter types because this is where T is used in many cases.

In my case it was a little bit different, because the return type of my function was T. In your case it seems that you haven't used T at all in your function. I guess you just simplified the example code.

So I have the following function

func getProperty<T>( propertyID : String ) -> T

And in case of, for instance

getProperty<Int>("countProperty")

the compiler gives me the error:

Cannot explicitly specialize a generic function

So, to give the compiler another source of information to infer the type of T from, you have to explicitly declare the type of the variable the return value is saved in.

var value : Int = getProperty("countProperty")

This way the compiler knows that T has to be an integer.

So I think overall it simply means that if you specify a generic function you have to at least use T in your parameter types or as a return type.


Swift 5

Typically there are many ways to define generic functions. But they are based on condition that T must be used as a parameter, or as a return type.

extension UIViewController {
    class func doSomething<T: UIView>() -> T {
        return T()
    }

    class func doSomethingElse<T: UIView>(value: T) {
        // Note: value is a instance of T
    }

    class func doLastThing<T: UIView>(value: T.Type) {
        // Note: value is a MetaType of T
    }
}

After that, we must provide T when calling.

let result = UIViewController.doSomething() as UIImageView // Define `T` by casting, as UIImageView
let result: UILabel = UIViewController.doSomething() // Define `T` with property type, as UILabel
UIViewController.doSomethingElse(value: UIButton()) // Define `T` with parameter type, as UIButton
UIViewController.doLastThing(value: UITextView.self) // Define `T` with parameter type, as UITextView

Ref:

  1. http://austinzheng.com/2015/01/02/swift-generics-pt-1/
  2. https://dispatchswift.com/type-constraints-for-generics-in-swift-d6bf2f0dbbb2

The solution is taking the class type as parameter (like in Java)

To let compiler know what type he is dealing with pass the class as argument

extension UIViewController {
    func navigate<ControllerType: UIViewController>(_ dump: ControllerType.Type, id: String, before: ((ControllerType) -> Void)?){
        let controller = self.storyboard?.instantiateViewController(withIdentifier: id) as! ControllerType
        before?(controller)
        self.navigationController?.pushViewController(controller, animated: true)
    }
}

Call as:

self.navigate(UserDetailsViewController.self, id: "UserDetailsViewController", before: {
        controller in
        controller.user = self.notification.sender
    })

You don't need a generic here since you have static types (String as parameter), but if you want to have a generic function call another you could do the following.

Using Generic methods

func fetchObjectOrCreate<T: NSManagedObject>(type: T.Type) -> T {
    if let existing = fetchExisting(type) {
       return existing
    }
    else {
        return createNew(type)
    }
}

func fetchExisting<T: NSManagedObject>(type: T.Type) -> T {
    let entityName = NSStringFromClass(type)
     // Run query for entiry
} 

func createNew<T: NSManagedObject>(type: T.Type) -> T {
     let entityName = NSStringFromClass(type)
     // create entity with name
} 

Using a generic class (Less flexible as the generic can be defined for 1 type only per instance)

class Foo<T> {

   func doStuff(text: String) -> T {
      return doOtherStuff(text)
   }

   func doOtherStuff(text: String) -> T {

   }  

}

let foo = Foo<Int>()
foo.doStuff("text")

I think that when you specify generic function you should specify some of the parameters of type T, like followed:

func generic1<T>(parameter: T) {
    println("OK")
}

func generic2<T>(parameter: T) {
    generic1(parameter)
}

and if you want to call handle() method, then you may do this by writing protocol, and specifying type constraint for T:

protocol Example {
    func handle() -> String
}

extension String: Example {
    func handle() -> String {
        return "OK"
    }
}

func generic1<T: Example>(parameter: T) {
    println(parameter.handle())
}

func generic2<T: Example>(parameter: T) {
    generic1(parameter)
}

so you may call this generic function with String:

generic2("Some")

and it will compile