Swfit3.0 reduce - Argument passed to call that takes no arguments [duplicate] - swift

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

Related

Swift: Why is this call ambiguous?

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

Swift function in class definition can't found another global function with similar name but different parameters [duplicate]

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

Return any type from a function in Swift

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

Infer closure return type from closure body when working with generics

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.

Swift Generic constraints in init

I have generic and I want to be able to initialize it with specific constrains. The constraints are only there for initialization. The rest of the class doesn't care. Here is a simplified example:
struct Generic<T> {
let compare: (T, T) -> Bool
init<T: Equatable>(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
insert(data)
}
init(compareHandler: (T, T) -> Bool, data[T]) {
compare = self.compareHandler
insert(data)
}
}
You can see there's two initializers. The second one obviously works fine. However, in the first one the local type T is mismatched with the struct's generic Type. So, for example, attempting to insert data I get Cannot invoke 'insert' with an argument list of type '([T])'. Is it possible for me to specialize the Struct's generic type only for the initialization or a specific function?
Note, I've already tried init<T where T:Equatable>(data: [T]) to the same effect.
Update
I'm using the following workaround: I create a top level function and removing the specialized init:
func equatableHandler<T: Equatable>(left: T, right: T) -> Bool {
return left == right
}
Clients of the struct can initialize using: Generic(compareHandler: equatableHandler, data: data)
It's not quite the "convenience" of using a specialized init, but I suppose it works well enough for my purposes. I'm not a fan of creating top-level functions, but the generic is used so often for "Equatable" generics that it makes sense for me to define the handler once for clients to use.
The problem is that the first init method
init<T: Equatable>(data: [T])
introduces a local type placeholder T which hides (and is completely
unrelated to) the placeholder T of the Generic type, so it
is essentially the same problem as in Array extension to remove object by value.
As of Swift 2 you can solve that with a "restricted extension":
extension Generic where T : Equatable {
init(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
// ...
}
}
For Swift 1.x the only solution is probably to define a global helper
function
func makeGeneric<T : Equatable>(data: [T]) -> Generic<T> {
return Generic(compareHandler: { $0 == $1 }, data: data)
}
(and I could not think of a sensible name for the function :).