Ambiguous method overload with closures in Swift, but only when closure returns a value
You are misunderstanding what's happening. It's not about returning a value. Simplify, for a clearer demonstration of that:
func call8(_: UInt8) -> String { "8" }
func call16(_: UInt16) -> String { "16" }
func ƒ(_ call: (UInt8) -> String) { call(8) }
func ƒ(_ call: (UInt16) -> String) { call(16) }
ƒ(call8) // "8"
ƒ(call16) // "16"
Instead, it's all about multiple lines. Read all about it!
https://forums.swift.org/t/multiline-closure-is-not-inferring-the-return-type/40013
As for the fix, you've got to explicitly type, for disambiguation. /p>
(string, arg: UInt8)
(string, arg: UInt16)
Is there shorthand to specify a specific overload when passing a function as a closure-based argument?
In Swift, the "base name" of a method is the method name without any arguments:
Foo.init(x:y:z:)
→Foo.init
Foo.bar(_:)
→Foo.bar
Foo.baz(baz:)
→Foo.baz
Foo.quux()
→Foo.quux
When referring to a method by name (rather than calling it), Swift will allow you to refer to it by its base name, so long as the usage is not ambiguous:
struct Foo {
func f(intValue: Int) {}
}
let f = Foo().f
However, when there are multiple methods with the same base name, you can run into situations with ambiguity:
struct Foo {
func f(intValue: Int) {}
func f(stringValue: String) {}
}
let f = Foo().f // error: ambiguous use of 'f'
When this happens, you can either:
Use explicit typing to help disambiguate the methods, if possible:
let f1: (Int) -> Void = Foo().f
let f2: (String) -> Void = Foo().fOr,
Refer to the method by its fully-qualified name (name with parameter names included):
let f1 = Foo().f(intValue:)
let f2 = Foo().f(stringValue:)
In your case, because both methods have the same type signature, you can't use approach (1) to disambiguate between the calls, and will have to resort to (2).
The issue you ran into is that the parameter name you were using was slightly off:
// ❌ Foo.init(doubleValue:)
// ✅ Foo.init(valueToDouble:)
let foos = values.map(Foo.init(valueToDouble:)) // ✅
This does work, and will work as a shorthand instead of having to call the method directly inside of a closure argument.
Ambiguous use of operator ''
The closure must explicitly declare the type of the s1
and s2
parameters and that type must implement >
operator. The typical way to do that is to make the signature of that closure ensure that the two parameters are (a) the same type; and (b) conform to the Comparable
protocol.
If you want simple2
to take any Comparable
type, rather than a closure, you could define a generic function:
func simple2<T: Comparable>(_ s1: T, _ s2: T) -> Bool {
return s1 > s2
}
Then you could call it with any Comparable
type.
Nested function overloading in Swift
IMHO this is clearer if you consider this variation:
func foo() {
let bar: (param: Int) -> () = { p in
// do stuff
}
func bar(param: Double) {
// do stuff
}
// call functions here
}
With your first bar
function definition you are just declaring a constant of type (param: Int) -> ()
.
Thus with your second declaration you are declaring another constant of different type (param: Double) -> ()
but having the same name as the already declared bar
.
In short it's just like you wrote:
let bar: Int = 0
let bar: Double = 0.0
In which case compiler will complain as well.
Hope this helps.
Swift inferred closure parameter puzzle
It is ambiguous. Both .times()
methods can be used with the given closure expression if the parameter type of the closure is not known.
If you just write { i in println("Year \(i)") }
, it is just a closure that takes one parameter of any type. Well, EVERY function type in Swift can be viewed as taking one parameter:
- What you think of as zero-parameter functions actually take one parameter of type
()
(a.k.a.Void
), of value()
, that's why the type is written as() -> something
- What you think of as multiple-parameter functions actually take one parameter of tuple type, a tuple of all the "multiple arguments", that's why the type is written as
(foo, bar) -> something
.
So, basically, your closure expression, without specifying the type of i
, can be inferred to ANY function type in Swift that returns Void
. The functions taken by both .times()
methods match this -- for the first .times()
method, it is inferred as a function of type () -> ()
, i.e. i
has type ()
; for the second .times()
method, it is inferred as a function of type Int -> ()
, i.e. i
has type Int
.
Related Topics
How to Get Exactly the Same Point on Different Screen Sizes
Realitykit - How to Add Motion to a Loaded Modelentity from Usdz File
Setting Observer for Swift Objects/Properties
Where to Place App Delegate Code in App.Swift File
Retrieve an Image from Firebase to an Uiimage Swift5
String Nil Inside Nsurlsession
Url Constructor Doesn't Work with Some Characters
How to Deal with Commas When Writing Objects to CSV in Swift
How to Loop All Firebase Children at Once in the Same Loop
Convert Integer to Roman Numeral String in Swift
Performing a Completion Handler Before App Launches
@Published Property Not Triggering Anything
Updating Switfui View When Coredata Changes