How to fix this curried function in Swift? - swift

The following example expands upon the example shown in this swift-evolution link, which describes only one parameter per argument list. Any suggestion on how to fix a two parameter argument list?
// Before: (yields warning)
func curried(x: Int)(y: String, z:String) -> Float {
return Float(x) + Float(y)! + Float(z)!
}
// After: (this is not working)
func curried(x: Int) -> (String, String) -> Float {
return {(y: String, z: String) -> Float in
return Float(x) + Float(y)! + Float(z)!
}
}
Xcode 7.3 still reports the second method as "Curried function declaration syntax will be removed in a future version of Swift; use a single parameter list."
Any help appreciated.

Ignore the Xcode 7.3 warning about the second version. If you clean out the build folder, the warning will probably go away. More important, the second version does work — it compiles in Swift 3, which is all that matters.

Related

What is the Swift compiler doing with my return type? Is it somehow casting?

I have a method:
func allRegions() -> [MappedRegion] {
return self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
}
I was frankly surprised this worked. I'm doing lazy stuff here, but it's apparently having a lazy sequence that turns into a sequence of MappedRegion be the same.
Then I was doing some poor mans timing and modified the function to read:
func allRegions() -> [MappedRegion] {
let startTime = Date()
let result = self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
self.sumRender += (Date() - startTime)
return result
}
But that created an error:
Cannot convert return expression of type 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<LazySequence<[StatusRowItem]>.Elements, ValveAbstract?>>, ValveAbstract>.Elements, [MappedRegion]>>>' (aka 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<Array<StatusRowItem>, Optional<ValveAbstract>>>, ValveAbstract>, Array<MappedRegion>>>>') to return type '[MappedRegion]'
That was initially a surprise. I found that if I specified the return type of result as [MappedRegion] all was happy (e.g. let result:[MappedRegion] = ...).
What is going on here? I get that the original one line function is inferring the result type as [MappedRegion], so I'm probably not getting much benefits from the lazy use. But what confuses me, is that this coercion from a lazy sequence to a fixed array automagically is reminiscent of casting in C, and I thought that Swift didn't do casting?
No, there is no casting going on. There are simply two different flatMap functions being called. LazyMapSequence has two flatMap(_:) functions (well, technically four, but two are deprecated).
In your first code block, this function is inferred (because this version of flatMap has a return type that matches your allRegions function's return type):
func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
And in your second code block, this function is inferred (because there is no type annotation on your local variable that's forcing it to choose the above version of flatMap):
func flatMap<SegmentOfResult>(_ transform: #escaping (Element) -> SegmentOfResult) -> LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<Base, Element>, SegmentOfResult>>> where SegmentOfResult : Sequence

Swift 5.2 tuple destructuring in closure has inconsistent behaviors

I ran into a weird tuple destructuring problem in Swift 5.2.
I thought tuple destructuring didn't work inside a closure parameter since some time ago.
And indeed, the following does not work:
let expected: ((Int, Int)) -> Void = { a, b in // does not compile
print(a, b)
}
However, I noticed that all of the below work:
func weird(closure: #escaping ((Int, Int)) -> Void) {
closure((1, 3))
}
// I can understand this
weird { print($0.0 + $0.1) }
weird { a, b in print(a + b) }
// Surprise!
weird { print($0 + $1) }
weird { p in print(p.0 + p.1) }
Did the last two examples worked before Swift 5.2? Is this behavior documented somewhere?
It is related to this proposal, which was once accepted in Swift 4.0.
SE-0110 Distinguish between single-tuple and multiple-argument function types
So, two of your examples (not last two though) caused error in a certain version of Swift, but Swift team found some unacceptable regression in this implementation.
Additional Commentary
And since a certain version of Swift (I do not remember the exact version, it might have been 4.0.x or 4.1), you can pass two argument closure to the parameter of function type taking a single tuple.
And recently, this exception is confirmed to be a part of SE-0110 and if some more modification is needed, a new proposal will be made and go through the usual Swift Evolution process.
Update on SE-0110 and SE-0155
the original proposal as reviewed did not include the special-case
conversion from (T, U, ...) -> V to ((T, U, ...)) -> V for function
arguments. In response to community feedback, this conversion was
added as part of the Core Team's acceptance of the proposal.
The Swift book may not have clear explanation of this behavior, but it surely is documented.

"ambiguous use" on generic method after migration to swift 4

I am trying to migrate my code from xcode 8.2 swift 3.0.2 to xcode 9 swift 4, and I have problem with this code:
func test<T0, TRet>(_ fn: (T0) -> TRet) -> Void {
print("foo1")
print(T0.self)
}
func test<T0, T1, TRet>(_ fn: (T0, T1) -> TRet) -> Void {
print("foo2")
print(T0.self)
print(T1.self)
}
let fn2 : (Int, Int) -> Int = { (x:Int, y:Int)->Int in
return x+y
}
test(fn2)
xcode 8.0.2, swift 3.0.2 results with:
foo2
Int
Int
xcode 9, swift 4 results with:
Playground execution failed:
error: MyPlayground.playground:12:1: error: ambiguous use of 'test'
test(fn2)
^
MyPlayground.playground:1:6: note: found this candidate
func test<T0, T1, TRet>(_ fn: (T0, T1) -> TRet) -> Void {
^
Am I missing something? Is there any new feature in swift 4 that causes this error?
Update
I filed a bug at bugs.swift.org as suggested in the comments.
https://bugs.swift.org/browse/SR-6108
I ran into the same problem, and stumbled across a workaround that is (for my purposes) nicer than disambiguating via naming. Perhaps it is not even a workaround, just the way things have to be. It's also possible that this is newly-possible in Swift 4.1 (not sure, since I migrated directly from Swift 3 to 4.1)
Change this:
func test<T0, TRet>( fn: (T0) -> TRet) -> Void
...to this...
func test<T0, TRet>( fn: ((T0)) -> TRet) -> Void
(note the extra pair of parens around the T0 callback parameter, which explicitly makes it into a tuple-of-1)
After this change, test(fn2) compiles and calls the test<T0,T1,TRet> overload.
It seems that the compiler is able to treat a function with N arguments as a function with one N-way-tuple argument. Hence, both the (T0) -> TRet and (T0,T1) -> TRet overloads are candidates for fn2, and the call is ambiguous. Adding 2nd pair of parens ((T0)) -> TRet limits that overload to an argument with a single parameter or 1-way tuple.

Swift 3 closure overload resolution

I'm confused by function overload resolution with closures in Swift 3.
For example, in the code:
func f<T>(_ a: T) {
print("Wide")
}
func f(_ a: (Int)->(Int)) {
print("Narrow")
}
f({(a: Int) -> Int in return a + 1})
I expect Narrow, not Wide, to be printed to the console. Can anyone explain why the more specific overload gets chosen for non-closure arguments but not for closures or is this a compiler bug?
Swift 2 exhibited the expected behavior.
This is probably due to the change in the default "escaping" behaviour for closure parameters.
If you change the specific function to:
func f(_ a:#escaping (Int)->Int)
{
print("Narrow")
}
it will print "Narrow" as expected (this is the same change that you probably had to make in several other places that were more obvious)

How to use a variadic closure in swift?

Is there a proper way to use a variadic parameter list in a closure in Swift?
In swift I notice that I can declare a function which takes a variadic argument list like so
protocol NumberType: Comparable, IntegerLiteralConvertible, IntegerArithmeticType {}
extension Int: NumberType {}
extension SequenceType where Generator.Element: NumberType {
func satisfy(closure:(args: Generator.Element...) -> ()) {
// Do something
closure(args: 1, 2, 3)
}
}
Which builds just fine. When I try to use the function:
[1, 2].satisfy { (args) in
print (args)
}
Xcode manages to auto complete as I would expect, but immediately upon closing the parenthesis after args, all syntax highlighting in Xcode disappears and I see a message "Command failed due to signal: Segmentation Fault: 11", which appears to just mean Xcode is super confused.
For context, I had planned on seeing if Swift could write a function which could return answers based on a variable number of parameters (mapping to the number of for loops required to get a brute force answer). It would be a simple way of testing the answer to a question such as "Given an array of Ints, find all combinations which satisfy the equation a^3 + b^3 = c^3 + d^3" with
let answer = array.satisfy ({ return pow($0, 3) + pow($1, 3) == pow($2, 3) + pow($3, 3) })
against a more optimal solution.
"Return all the 2s" would just be
let answer = array.satisfy ({ return $0 == 2 })
A single for loop
Compiler limitation/bug with argument type inference for single-expression closures
I believe the source of this is a current limitation (/bug) in the compiler w.r.t. inferring the argument types in single-line closures using variadic parameters, see e.g. the following Q&A
Why can't I use .reduce() in a one-liner Swift closure with a variadic, anonymous argument?
A similar issue was also present for inout arguments in Swift 2.1 (but no longer in 2.2), as is explained in the following thread
Inline if statement mutating inout parameter in a void return closure, weird error (Error: type 'Int1' does not conform to protocol 'BooleanType')
Looking at thread 1. as well as attempting to find the described bug flagged in Swift JIRA, however, it seems as if the OP of thread 1. never filed a bug for this, after all. Possibly I just haven't found an existing bug report, but if none exists, one should possibly be filed.
Current workarounds
Possible workarounds, until the compiler's closure argument type inference catches up, are
Extend the closure beyond single-line body
// ...
[1, 2].satisfy { (args) in
() // dummy
print (args) // [1, 2, 3]
}
Or, explicitly include type of args, e.g.
[1, 2].satisfy { (args: Int...) in
print (args) // [1, 2, 3]
}
Note that Generator.Element resolves to Int in this example above.
Current status for Swift 3.0-dev
As mentioned briefly above, curiously enough, this bug
inout: is apparently no longer present in Swift 2.2 or Swift 3.0-dev for inout arguments, w.r.t. the issues described in Q&A 2. as linked to above
it was possibly fixed as bug [SR-7] was resolved (-> Swift 2.2)
however, seems to be regression 2.2->3.0-dev, w.r.t. type inference for inout arguments, as reported in bug report [SR-892]. E.g. the following snippet works in Swift 2.2, but not in 3.0-dev (minimally modified snipper from bug report [SR-7])
func f(inout a: Int) {}
let g = { x in f(&x) } // OK 2.2, crashes 3.0-dev
variadic: is still present in Swift 2.2 as well as Swift 3.0-dev for variadic arguments (this thread and Q&A 1. above).
a more condensed example of the bug:
let a: (Int...) -> () = { (args) in print(args) } // bug: crashes
let b: (Int...) -> () = { (args: Int...) in print(args) } // explicitly state argument type, OK
let c: (Int...) -> () = { (args) in (); print(args) } // extend to more than single line closure, OK
(For Swift 3.0-dev, tested using the IBM Swift Sandbox running Swift 3.0-dev.