Swift 3.0: compiler error when calling global func min <T> (T, T) in an array or dictionary extension

After converting from Swift 2.2 to 3.0, my Array extension is no longer compiled since it contains a function call to the global standard library min<T>(T,T) and shows extra argument in call compiling extra argument in call .

Here is an easy 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 the Dictionary extension, while the same code compiles just in the extension of other types (for example, String or AudioBuffer ):

compiler errors in Array and Dictionary extensions

Looking at the Array and Dictionary documentation, I found that there are instance methods in Sequence named public func min() β†’ Element? and public func min(by areInIncreasingOrder: (Element, Element) throws β†’ Bool) rethrows β†’ Element? Although both String and AudioBuffer do not have any min(...) function.

Is it possible that it is for this reason that I cannot name a global function? The compiler cannot distinguish between global func min<T>(T,T) and self.min(...) although they have completely different signatures?

Is this a bug or a function? What am I doing wrong? How can I properly call min(T,T) inside an Array extension?

+6
source share
1 answer

I see no reason why the compiler will not be able to resolve this function call, so I would consider it an error (it has already been registered - see SR-2450 ).

It seems that this happens when trying to call a top-level function with the same name, but with a distinctly different signature for the method or property accessible from the same area in the specified type (instance or static).

An even simpler example:

 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 } } 

Before a fixed, a simple solution would be to prefix the call with the name of the module in which it is located, to eliminate that you are referring to a top-level function, not an instance. For the standard library, this is Swift :

 extension Array { func smallestInt(first: Int, second: Int) -> Int { return Swift.min(first, second) } } 

In Swift 4, the compiler has better diagnostics for this error (although the fact that it is still an error is an IMO error):

 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 it is interesting that the compiler now also warns of trying to call the standard library method with the same name as the top-level function stdlib:

 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 warns, you can disable it using explicit self. :

 extension Array where Element : Comparable { func smallest() -> Element? { return self.min() } } 

Although what is really interesting about this warning does not seem to apply to non-stdlib specific functions:

 func foo(_ a: Int) {} struct Foo { func foo() {} func bar() { foo() // no warning... } } 
+9
source

All Articles