Why does the following code yield an "Ambiguous use of 'foo'" compile error? I'd think that the return value makes it clear which one of the foo() overloads should be called.
Even more interestingly, why does the error disappear if I remove the print("x") line? What difference does that make?
(Xcode 10.2.1, Swift 5, default build settings for a new project.)
func foo(_: () -> Int) {}
func foo(_: () -> String) {}
func bar() {
foo() {
print("x")
return 42
}
}
Type inference only applies to single-expression closures, so the compiler doesn't attempt to infer the type of the closure based on the return expression because there are two expressions (the print and the return). It then tries to infer the return type based on the return type of the closure passed to foo, but it finds two different foos and can't decide which one to use, so it then complains of an ambiguous use of foo. If you explicitly declare the type of the closure, the following code will compile:
func bar() {
foo() { () -> Int in
print("x")
return 42
}
}
Related
After converting from Swift 2.2 to 3.0 my Array extension does not compile anymore, because it contains a call to global standard library function min<T>(T,T) and shows compiler error extra argument in call.
Here's a simple way to reproduce the error:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return min(first, second) // compiler error: "Extra argument in call"
}
}
I get the same error when adding the same function to an extension of Dictionary, while the exact same code compiles just fine in an extension of other types (e.g. String or AudioBuffer):
Looking at the documentation of Array and Dictionary, I find that there are instance methods on Sequence named public func min() -> Element? and public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?. While both String and AudioBuffer do not have any kind of min(...) function.
Is it possible that this is the reason why I can't call the global function? The compiler can't distinguish between global func min<T>(T,T) and self.min(...) although they have completely different signatures?
Is this a bug or a feature? What am I doing wrong? How can I call min(T,T) correctly inside an Array extension?
I see no reason why the compiler shouldn't be able to resolve this function call, therefore I would consider it a bug (it has already been filed – see SR-2450).
It seems to occur whenever attempting to call a top-level function with the same name, but unambiguously different signature to a method or property that's accessible from the same scope in a given type (instance or static).
An even simpler example would be:
func foo(_ a: Int) {}
struct Foo {
func foo() {} // or static func foo() {}, var foo = 0, static var foo = 0
func bar() {
foo(2) // error: argument passed to call that takes no arguments
}
}
Until fixed, a simple solution would be to prefix the call with the name of the module in which it resides in order to disambiguate that you're referring to the top-level function, rather than the instance one. For the standard library, that's Swift:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return Swift.min(first, second)
}
}
In Swift 4, the compiler has a better diagnostic for this error (though the fact that it's still an error is a bug IMO):
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
// Use of 'min' refers to instance method 'min(by:)'
// rather than global function 'min' in module 'Swift'
// - Use 'Swift.' to reference the global function in module 'Swift'
return min(first, second)
}
}
Although what's interesting is that the compiler will now also warn on attempting to call a standard library method with the same name as a stdlib top-level function:
extension Array where Element : Comparable {
func smallest() -> Element? {
// Use of 'min' treated as a reference to instance method in protocol 'Sequence'
// - Use 'self.' to silence this warning
// - Use 'Swift.' to reference the global function
return min()
}
}
In this case, as the warning says, you can silence it by using an explicit self.:
extension Array where Element : Comparable {
func smallest() -> Element? {
return self.min()
}
}
Although what's really curious about this warning is it doesn't appear to extend to non-stdlib defined functions:
func foo(_ a: Int) {}
struct Foo {
func foo() {}
func bar() {
foo() // no warning...
}
}
After converting from Swift 2.2 to 3.0 my Array extension does not compile anymore, because it contains a call to global standard library function min<T>(T,T) and shows compiler error extra argument in call.
Here's a simple way to reproduce the error:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return min(first, second) // compiler error: "Extra argument in call"
}
}
I get the same error when adding the same function to an extension of Dictionary, while the exact same code compiles just fine in an extension of other types (e.g. String or AudioBuffer):
Looking at the documentation of Array and Dictionary, I find that there are instance methods on Sequence named public func min() -> Element? and public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?. While both String and AudioBuffer do not have any kind of min(...) function.
Is it possible that this is the reason why I can't call the global function? The compiler can't distinguish between global func min<T>(T,T) and self.min(...) although they have completely different signatures?
Is this a bug or a feature? What am I doing wrong? How can I call min(T,T) correctly inside an Array extension?
I see no reason why the compiler shouldn't be able to resolve this function call, therefore I would consider it a bug (it has already been filed – see SR-2450).
It seems to occur whenever attempting to call a top-level function with the same name, but unambiguously different signature to a method or property that's accessible from the same scope in a given type (instance or static).
An even simpler example would be:
func foo(_ a: Int) {}
struct Foo {
func foo() {} // or static func foo() {}, var foo = 0, static var foo = 0
func bar() {
foo(2) // error: argument passed to call that takes no arguments
}
}
Until fixed, a simple solution would be to prefix the call with the name of the module in which it resides in order to disambiguate that you're referring to the top-level function, rather than the instance one. For the standard library, that's Swift:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return Swift.min(first, second)
}
}
In Swift 4, the compiler has a better diagnostic for this error (though the fact that it's still an error is a bug IMO):
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
// Use of 'min' refers to instance method 'min(by:)'
// rather than global function 'min' in module 'Swift'
// - Use 'Swift.' to reference the global function in module 'Swift'
return min(first, second)
}
}
Although what's interesting is that the compiler will now also warn on attempting to call a standard library method with the same name as a stdlib top-level function:
extension Array where Element : Comparable {
func smallest() -> Element? {
// Use of 'min' treated as a reference to instance method in protocol 'Sequence'
// - Use 'self.' to silence this warning
// - Use 'Swift.' to reference the global function
return min()
}
}
In this case, as the warning says, you can silence it by using an explicit self.:
extension Array where Element : Comparable {
func smallest() -> Element? {
return self.min()
}
}
Although what's really curious about this warning is it doesn't appear to extend to non-stdlib defined functions:
func foo(_ a: Int) {}
struct Foo {
func foo() {}
func bar() {
foo() // no warning...
}
}
I am attempting to create a function that can return any type. I do not want it to return an object of type Any, but of other types, i.e. String, Bool, Int, etc. You get the idea.
You can easily do this using generics in this fashion:
func example<T>(_ arg: T) -> T {
// Stuff here
}
But is it possible to do it without passing in any arguments of the same type? Here is what I am thinking of:
func example<T>() -> T {
// Stuff here
}
When I try to do this, everything works until I call the function, then I get this error:
generic parameter 'T' could not be inferred
is it possible to do it without passing in any arguments of the same type?
The answer is yes, but there needs to be a way for the compiler to infer the correct version of the generic function. If it knows what it is assigning the result to, it will work. So for instance, you could explicitly type a let or var declaration. The below works in a playground on Swift 3.
protocol Fooable
{
init()
}
extension Int: Fooable {}
extension String: Fooable {}
func foo<T: Fooable>() -> T
{
return T()
}
let x: String = foo() // x is assigned the empty string
let y: Int = foo() // y is assigned 0
I think best if I start with an example:
class Test<T> {
func test(closure: (T) -> Void) { }
func test(closure: (T) -> T) { }
func test(closure: (T) -> Test<T>) { }
}
Test<Int>().test { a in }
The code above gives the following error:
error: ambiguous use of 'test'
This is because the Swift compiler doesn't know to which one of the three methods is should map the call to. But from the closure body it's quite clear that it returns a Void, so it should pick the first method.
Looks like the Swift compiler cannot determine to which method overload to map the call to based on the closure body. If I explicitly specify the closure signature, then the problem goes away:
Test<Int>().test { (a: Int) -> Void in }
My question is: can I somehow instruct Swift to pick-up the correct overload for short-hand closure expressions like the one in discussion, or will I have to explicitly declare the closure signature?
Actually, it seems that I was pushing the compiler limits too hard (as #Martin R pointed in the comments). The { a in } closure was kinda incomplete, since the compiler had no statements to infer the closure return type from.
This works:
Test<Int>().test { (a: Int) -> Void in () }
Same as the following:
func doNothing() { }
Test<Int>().test { (a: Int) -> Void in doNothing() }
In the above examples the compiler is provided with the minimum amount of information to determine which overload to pick.
Below you'll see a playground where I try to illustrate my problem. I have a class (Foo) with some overloaded generic methods (bar<T>()) whose return types depends on the generic parameter. I have 3 methods:
One must return a subclass of a specific type (in the example below it is called BaseClass)
Other one must return a Array of instances of this specific type.
The last should be used as default one if the other two conditions are not fulfilled.
The problem comes when I call the method. Even if I tell the compiler what is the type I am expecting, it gives me the error Ambiguos use of bar().
import UIKit
class BaseClass {
required init() {}
}
class Foo {
// 1
func bar<T: BaseClass>() -> T? {
// Just a default implementation, it should do real work inside
return T()
}
// 2
func bar<T: BaseClass>() -> [T]? {
// Just a default implementation, it should do real work inside
return []
}
// 3
func bar<T>() -> T? {
// Just a default implementation, it should do real work inside
return "Test" as? T
}
}
let foo = Foo()
// Should call "1", because it return type is BaseClass
let baseClassObject: BaseClass? = foo.bar()
// Should call "2", because it return type is [BaseClass]
let baseClasArray: [BaseClass]? = foo.bar()
// Should call "3", because it return type is neither BaseClass nor [BaseClass]
let anyOtherObject: String = foo.bar()
In my opinion, the compiler should know what method call, cause I am telling it the return type, right? is this a limitation with generics or am I missing something?
Thanks in advance.
Update 19th April
In an answer they say that the conflicts comes because "BaseClass" can be interpreted as BaseClass but also as T. But in this modified playground, the compilers does infers which method use properly. Is there any difference? should I have the same conflict here?:
import UIKit
class BaseClass {
required init() {}
}
class Foo {
// 1
func bar<T: BaseClass>(param: T) -> String {
return "I am BaseClass"
}
// 2
func bar<T: BaseClass>(param: [T]) -> String {
return "I am [BaseClass]"
}
// 3
func bar<T>(param: T) -> String {
return "I am other thing"
}
}
let foo = Foo()
// It prints "I am BaseClass"
foo.bar(BaseClass())
// It prints "I am [BaseClass]"
foo.bar([BaseClass(), BaseClass()])
// It prints "I am another thing"
foo.bar(NSObject())
Number 3 causes conflict with the other functions
This is because < T > could also be of type BaseClass and of type [BaseClass]. The compiler simply sees an interface of "throw anything in here" which will conflict with any more specific level of specificity.