Quick function call function with return function

just a quick question. I have the following code that works fine:

class obA: Printable { var description: String { get { return "obA" } } } class obB: Printable { var description: String { get { return "obB" } } } func giveObject() -> obA { return obA() } func giveObject() -> obB { return obB() } var a: obA = giveObject() var b: obB = giveObject() println(a) println(b) 

The correct version of the giveObject is called, and all is well. Of course, this is just a simplified case, in fact, in my project there are several dozen "giveObject" overloads, all different in return type. Now I want to create a general function to analyze all these things. So the next step:

 func giveGeneric<T>() -> T { return giveObject() } var c: obA = giveGeneric() println(c) 

And it complains about the ambiguous use of giveObject. I can understand where the error comes from, but I don’t see right away how I can solve it, and I use this design ...

+5
source share
2 answers

First of all, just a note.

If the generic type giveGeneric just T , then it can be anything (String, Int, ...). So how to react in this case giveObject() ?

I mean, if you write:

 let word : String = giveGeneric() 

internally, your generic function calls something like:

 let result : String = giveObject() // Ambiguous use of giveObject 

My decision

I declared the protocol as follows:

 protocol MyObject { init() } 

Then I made your 2 classes conform to the protocol

 class obA: Printable, MyObject { var description: String { get { return "obA" } } required init() {} } class obB: Printable, MyObject { var description: String { get { return "obB" } } required init() {} } 

Finally, I can write this

 func giveGeneric<T:MyObject>() -> T { return T() } 

Now I can use it:

 let a1 : obA = giveGeneric() let b1 : obB = giveGeneric() 

You decided that this is the solution you were looking for, or just a workaround.

+3
source

This will not work even if you implement the giveObject function for any possible type. Since T can be of any type, the giveGeneric method cannot determine the correct overload for the call.

The only way I can think of is to create tremendous speed with as many cases as the number of types you want to handle:

 func giveGeneric<T>() -> T? { switch "\(T.self)" { case "\(obA.self)": return giveObject() as obA as? T case "\(obB.self)": return giveObject() as obB as? T default: return .None } } 

But I don’t think that I would use such a solution even with a gun aimed at my head - it’s really ugly.

If in all your cases you create instances using the constructor without parameters, you can create a protocol and restrict the T generic type for its implementation:

 protocol Instantiable { init() } func giveGeneric<T: Instantiable>() -> T { return T() } 

You can use with both built-in and new types - for example:

 extension String : Instantiable { // `String` already implements `init()`, so nothing to add here } let s: String = giveGeneric() 

Alternatively, if you prefer, you can force the protocol to declare a static giveObject method, rather than a constructor without parameters:

 protocol Instantiable { static func giveObject() -> Self } func giveGeneric<T: Instantiable>() -> T { return T.giveObject() } extension String : Instantiable { static func giveObject() -> String { return String() } } let s: String = giveGeneric() 
+3
source

All Articles