How to disambiguate functions with differences only in parameter names in Swift - swift

I have the following functions:
func moveThing(thing: AnyObject, toLeft length: Int) {}
func moveThing(thing: AnyObject, toRight length: Int) {}
However, when I pass one of the functions as a parameter, compiler complains about "Ambiguous use of 'moveThing'"
func exec(function: (AnyObject, Int) -> ()) {}
exec(moveThing) // Apparently ambiguous
exec(moveThing as (AnyObject, toLeft: Int) -> ()) // Still ambiguous
How can I solve the ambiguity?

Swift Evolution proposal SE-0021 addressed this by allowing moveThing(_:toLeft:) to disambiguate these functions, and it is implemented in Swift 2.2.

I know this is an old thread, but I ran into this related situation recently. Might help somebody.
TLDR
Ultimately I solved the problem by just wrapping the method call in a closure like this:
let cancel: (Text) -> Alert.Button = { .cancel($0) }
Long Winded Explanation
When I type Alert.Button.cancel (from the SwiftUI framework), auto-complete shows me these options:
cancel(action: (() -> Void)?) // 1
cancel(label: Text) // 2
cancel() // 3
cancel(label: Text, action: (() -> Void)?) // 4
Naturally I thought this bit of code should work:
let cancel: (Text) -> Alert.Button = Alert.Button.cancel(_:)
However, the compiler says Cannot convert value of type '((() -> Void)?) -> Alert.Button' to specified type '(Text) -> Alert.Button'. Apparently it translates that signature to mean method 1 instead of method 2.
As it turns out, method 2 does not actually exist. Looking at the actual declarations in Alert.swift we find:
public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
public static func cancel(_ action: (() -> Void)? = {}) -> Alert.Button
So, cancel(label:) is rendered by auto-complete from cancel(_:action:) because the parameter action has a default value.
Conclusion: I made the mistake of assuming auto-complete was showing me individual method declarations. If the compiler tells you a method signature doesn't match what you expect, check the method declaration.

An interesting question! I don't think you can at the moment, as it seems that parameter names are not part of the function reference name, though I couldn't find anything from Apple's reference documentation that explicitly dictates this.
Of course, for this particular example, you can use
exec({ moveThing($0, toLeft: $1) } )
exec({ moveThing($0, toRight: $1) } )
but I see what you are after with the simplified example.

Related

Swift.Bool isn't a Bool?

I had a function
func login<Bool> (parameters: [(String, Any)],
completion: #escaping (Bool) -> Void) {
//Do something
}
And whenever I called the completion handler like so
completion(false)
or
completion(true)
XCode kept telling me: "Cannot convert value of type 'Swift.Bool' to expected argument type 'Bool'"
Eventually, I removed the at the beginning of the function, and the error went away. I thought that was declaring the type for the function, but I'm frankly not sure what that means, or what <> does despite googling. I'm sure it's explained well, but I'm not grasping the concept from googling alone. And why is Swift.Bool not able to be converted to Bool. I was able to find that there is an objective C version of bool and I thought maybe it was asking for that, but that didn't work either. What does that mean a Bool is?
The syntax func login<Bool> defines a type parameter called Bool. It has nothing to do with Swift.Bool. It's just a name you've defined. It's the same as if you declared a local variable var Bool: String. You'd have a variable named Bool that is actually a String. Don't do that.
If you want the value to always be Bool, remove the type parameter. This isn't generic.
func login(parameters: [(String, Any)],
completion: #escaping (Bool) -> Void) {
For details on the <...> syntax and generics see Generics in The Swift Programming Language.

escaping closure in swift

I have read a lot of material on stack overflow and I just cannot figure this one out:
I have been this line of code from an online source for hours and I just don't know why the closure that is being passed into a function is escaping, here is the code:
func composeFunction(functionA: #escaping (Int) -> String, functionB: #escaping (String) -> String) -> ((Int) -> String) {
return {
number in
functionB(functionA(number))
}
}
From apple's documentation, closures are escaping when:
1) Asynchronous operation that runs on a background thread
2) The closure is interactive with properties outside of it's scope (using self)
But I don't see those are happening, many help will be appreciated!
Thanks!
your func composeFunction returns a ((Int) -> (String)) and that is exactly a closure. Of course now this means functionA and functionB are going to be escaping because we don't know when and where this closure will be called. Moreover, this is because it needs to know if it should keep the reference to the objects passed in / being manipulated. For example, if all your closure parameters had (() -> Void) instead and you also returned (() -> Void) then it would not need to be escaping.
{
number in
functionB(functionA(number))
}
is a closure. Returning it causes both functionB and functionA to escape, because it becomes unknown at what point this closure will be called or deallocated.
This is different from just return functionB(functionA(number)), which causes the immediate invocation of both of those functions, and causes them to never escape the composeFunction context.

Swift 3: Inheritance from non-named type

I have the following SSCIE:
protocol Foo {
associatedtype Bar
associatedtype Baz: (Self.Bar) -> Void
var currentValue: Bar { get }
}
That I want to use like this:
func call<T: Foo>(foo: T, callback: #escaping T.Baz) {
DispatchQueue.main.async {
callback(foo.currentValue)
}
}
But it fails to compile, with the error:
Inheritance from non-named type '(`Self`.Bar)'
This also fails to compile when I use (Bar) -> Void and (Foo.Bar) -> Void.
Sadly, Googling this didn't come up with any useful results.
Does anyone have any idea what this error means, what I'm doing wrong, and how to correct it?
Associated types in Swift 3 can only be "is-a"-constrained. So your Bar is required to be an Any. Which, by the way, is not much of a constraint ;). In other words, you can remove it.
However, (Self.Bar) -> Void is a function type and you can't constrain an associated type like this.
If you want to define a callback type, you can use a typealias:
protocol Foo
{
associatedtype Bar
typealias Callback = (Self.Bar) -> Void
var currentValue: Bar { get }
func f(callback: Callback) -> Void
}
Using #escaping does not currently work in a typealias (see SR-2316 and its various duplicates). This is a bug that was supposed to have a fix soon (as of August 2016). So you will have to spell it out for now:
func call<T: Foo>(foo: T, callback: #escaping (T.Bar) -> Void) {
DispatchQueue.main.async {
callback(foo.currentValue)
}
}
Update: As Hamish suggested, I filed SR-4967. I'll update this post as soon as there is any news about it.
As already mentioned, function types can't be used as associated types.
Try this instead:
func call<T: Foo>(foo: T, callback: #escaping (T.Bar) -> Void) {
...
}
and using this design you can mix-and-match function types (for the callback arg) for each specific helper function (call in your example) you come up with.

Trouble with non-escaping closures in Swift 3

I have an extension Array in the form of:
extension Array
{
private func someFunction(someClosure: (() -> Int)?)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
But I'm getting the error: Passing non-escaping parameter 'someOtherClosure' to function expecting an #escaping closure.
Both closures are indeed non-escaping (by default), and explicitly adding #noescape to someFunction yields a warning indicating that this is the default in Swift 3.1.
Any idea why I'm getting this error?
-- UPDATE --
Screenshot attached:
Optional closures are always escaping.
Why is that? That's because the optional (which is an enum) wraps the closure and internally saves it.
There is an excellent article about the quirks of #escaping here.
As already said, Optional closures are escaping. An addition though:
Swift 3.1 has a withoutActuallyEscaping helper function that can be useful here. It marks a closure escaping only for its use inside a passed closure, so that you don't have to expose the escaping attribute to the function signature.
Can be used like this:
extension Array {
private func someFunction(someClosure: (() -> Int)?) {
someClosure?()
}
func someOtherFunction(someOtherClosure: () -> Int) {
withoutActuallyEscaping(someOtherClosure) {
someFunction(someClosure: $0)
}
}
}
let x = [1, 2, 3]
x.someOtherFunction(someOtherClosure: { return 1 })
Hope this is helpful!
The problem is that optionals (in this case (()-> Int)?) are an Enum which capture their value. If that value is a function, it must be used with #escaping because it is indeed captured by the optional.
In your case it gets tricky because the closure captured by the optional automatically captures another closure. So someOtherClosure has to be marked #escaping as well.
You can test the following code in a playground to confirm this:
extension Array
{
private func someFunction(someClosure: () -> Int)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
let f: ()->Int = { return 42 }
[].someOtherFunction(someOtherClosure: f)

Swift trailing closure stopped working when I moved the class into a Framework

I had a LocationManager class the performs various tasks and uses trailing closure.
Here is a method signature :
func getAdresseForLocation(location: CLLocationCoordinate2D, addressType: LocationManagerAddressType, completion: (Address?) -> Void)
For various reasons, I decided to move some file into a Framework, donc I declared my class and method public as follows :
public func getAdresseForLocation(location: CLLocationCoordinate2D, addressType: LocationManagerAddressType, completion: (Address?) -> Void)
But now I get a compilation error from the trailing closure :
Cannot convert value of type '(Address?) -> ()' to expected argument type '(Address?) -> (Void)'
I tried to change the return type to (), (Void), return Void or (Void) from the closure, nothing works.
Do you have any idea what's going on?
Thakns.
Try:
completion: ((Address)? -> Void))