I'd like to understand why the expanded method works while the nil-coalescing operator version tells that there is some ambiguity trying to compile it.
typealias SendBlock = ([NSArray]) -> Void
var callbacks = [SendBlock]()
func functionWithArgs(callback: SendBlock?) {
callbacks.append(callback ?? { _ in })
}
func functionWithArgsExpanded(callback: SendBlock?) {
if let cb = callback {
callbacks.append(cb)
} else {
callbacks.append({ _ in })
}
}
It’s because of the #autoclosure used on the rhs argument of ??. Something about that means it doesn’t like actually receiving a closure as the type of the thing being coalesced.
Just to demonstrate the location of the issue (don’t do this as a workaround), if you redefine a version of ?? without it, it’s fine:
typealias SendBlock = () -> Void
var callbacks = [SendBlock]()
infix operator !! { }
func !!<T>(optional: T?, defaultValue: T)->T {
return optional != nil ? optional! : defaultValue
}
func functionWithArgs(callback: SendBlock?) {
callbacks.append( callback !! { _ in })
}
functionWithArgs { _ in println("blah") }
// just to prove it works… prints “blah”
for x in callbacks { x() }
But if you amend the operator to use an #autoclosure:
func !!<T>(optional: T?, #autoclosure defaultValue: ()->T)->T {
return optional != nil ? optional! : defaultValue()
}
You get your error:
error: type of expression is ambiguous without more context
callbacks.append( callback !! { _ in })
^
I’d say this is a bug and you should file a report. In the mean-time your workaround is probably the best you’ll do.
I think it's just a bug in the compiler. It works just fine if you substitute String every place you have SendBlock.
Evidently, the compiler chokes on the use of the nil-coalescing operator with an Optional wrapping a function type. You get a more revealing error if you write it like this:
func functionWithArgs(callback: SendBlock?) {
let sb : SendBlock = { _ in }
callbacks.append(callback ?? sb)
}
The error reads: "Binary operator ?? cannot be applied to operands of type SendBlock? and SendBlock." To which one wants to reply: Of course it can! Those are exactly the sorts of operand to which it can be applied: an Optional and its unwrapped form.
Related
I understand why this produces a compiler error:
let initialProducer = SignalProducer<Int, NoError>(value:42)
let sideEffectProducer = initialProducer.on(next: { (answer: Int) in
return _
})
The error is
Cannot convert value of type '(Int) -> _' to expected argument type
'(Int -> ())?'
So the next parameter takes a closure with an Int parameter that returns Void whilst we're returning _
But why does this compile fine:
let initialProducer = SignalProducer<Int, NoError>(value:42)
let sideEffectProducer = initialProducer.on(next: { (answer: Int) in
return ""
})
we're returning a String, not Void so why does the compiler not complain?
_ isn't nothing. It is a pattern, or a part of a pattern that can match anything. It can also be used in an assignment statement to show that you don't care about the result.
_ = foo() // Ignore result returned from foo
In your closure, if you want to return nothing, then either:
return
or omit the return altogether if you're at the end of the closure.
If you return _, Swift cannot figure out the signature of your closure. You can demonstrate that by doing:
let bar = { return _ } // Unable to infer closure return type in current context
If you remove the _, it compiles fine since bar becomes a () -> ().
Swift could have given you a better error message like it does if you try to return _ from a function:
func foo() {
return _ // '_' can only appear in a pattern or on the left side of an assignment
}
So, why does return "" work? Here's a clue.
There are some apparent oddness around single-line closures. Consider the following example which is similar to yours:
func doit(handler: (Int) -> ()) {
handler(17)
print("doit is done")
}
doit() { (answer: Int) in
//print(answer + 1)
return ""
}
Running this produces the output:
doit is done
So, like your example doit is expecting a (Int) -> () closure, but we're passing a (Int) -> String closure. And it works...
But, if you un-comment the print(answer + 1) line, the return "" then results in the error:
Unexpected non-void return in void function
I am trying to reduce an array of Bools by applying the logical operator OR (||) using the following code, however I get an error:
func reduceBools(values: [Bool]) -> Bool {
return values.reduce(false, combine: ||)
}
Ambiguous reference to member '||'
Analogously for integers the code works like a charm.
func reduceInts(values: [Int]) -> Int {
return values.reduce(0, combine: +)
}
I was able to make it work by adding a || function (code below) or using a { $0 || $1 } closure but I dislike these approaches and I would prefer simply passing the operator.
func ||(lhs: Bool, rhs: Bool) -> Bool {
return lhs || rhs
}
The same thing happens for the logical AND (&&) operator.
How can I make it work without using the hack above?
As an alternative, you could use the following approach
// ||
func reduceBoolsOr(values: [Bool]) -> Bool {
return values.contains(true)
}
// &&
func reduceBoolsAnd(values: [Bool]) -> Bool {
return !values.contains(false)
}
Note that .reduce comes with an overhead. If the end result is the importance of your question (rather than enquiring above the unexpected behaviour of || and && operators in this context), then perhaps the pragmatic approach above can be of help, even if it doesn't really reduce the array, however producing the same result due to the simple nature of the boolean type.
Swift 4.2+ / Xcode 10.0+
In modern versions of Swift there is allSatisfy function, which checks all elements for satisfying some rule.
In OP's case:
values.allSatisfy { $0 }
UPD:
To make this work for OR, do
!values.allSatisfy{!$0}
Thanks to Andy Weinstein
Following approach will work
values.reduce(false) { $0 || $1 }
Ambiguous reference to member '||' means, that there are more than one possible candidates, from which compiler is not able to choose. In your case those are
public func ||<T : BooleanType, U : BooleanType>(lhs: T, #autoclosure rhs: () throws -> U) rethrows -> Bool
and
public func ||<T : BooleanType>(lhs: T, #autoclosure rhs: () throws -> Bool) rethrows -> Bool
probably your 'hack' using a { $0 || $1 } is the best solutions here.
This happens because of Swifts closure semantics. It takes your arguments and applies function to them, omitting argument names.
protocol Numeric {
...
public static func +(lhs: Self, rhs: Self) -> Self
...
}
In example with Ints, you would pass (Int, Int) into a closure, and + function in Numeric protocol expects exactly two ints to sum them.
Thats why code like below works just fine
[1, 2, 3, 4].reduce(0, +)
Because you just took 2 ints, and applied function, which takes just two ints.
If you write your own function, which would take just two argument, it would work as well.
func myOwnAwesomeFunc<T: Numeric>(a: T, b: T) -> T { in
return 1 // production ready
}
[1, 2, 3, 4].reduce(0, myOwnAwesomeFunc) // prints 1
Good so far. But why can't we write
[true, false, true].reduce(false, ||) // yields Cannot invoke 'reduce'
// with an argument list of type
// '(Bool, (Bool, #autoclosure () throws -> Bool) throws -> Bool)'
That's because this operator takes bool and a closure, which returns bool. Not bool, closure!
But if it is like this, why aren't we writing true || { false }() ?
Thats because of #autoclosure, which takes care of curly braces for us.
Main question, why is it implemented this way, so we can't use Swifts awesome short-hand closure syntax with booleans? Idk
Here's another approach, I modified the reduceBools function to take the operator as a parameter -
typealias LogicalOperator = ((Bool, #autoclosure () throws -> Bool) throws -> Bool)
func reduceBools(values: [Bool], combine: LogicalOperator) -> Bool {
var started: Bool = false
return values.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value // obviously up to you how you'd handle the try/catch
started = true
})
}
let bools = [true, false, false, true]
let result1 = self.reduceBools(values: bools, combine: ||)
print(result1) // prints true
let result2 = self.reduceBools(values: bools, combine: &&)
print(result2) // prints false
Or it could be more useful as an extension of Sequence -
extension Sequence where Element == Bool {
func reduce(_ combine: LogicalOperator) -> Bool {
var started: Bool = false
return self.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value
started = true
})
}
}
print(bools.reduce(||)) // prints true
I am trying to solve a separate problem related to parsing JSON. In the process, I ran afoul of the Swift compiler, as I expected it to use closure template arguments to select a function overload for optional types.
I haven't seen anything explicit in their documentation on this topic, but is it not the expectation that all else equal, swiftc will use arguments of a closure parameter in a generic function to select the correct overload?
Here is the simplest sample that I could come up with:
import Foundation
let os:NSString = "foo!"
let d:[String:AnyObject] = ["a": os]
struct Model {
var opt:String?
var basic:String = ""
}
func read<T>(source:AnyObject?, set:T -> ()) {
if let t:T = source as? T {
println("basic: read type: \(T.self) from value \(source)")
}
else {
println("failed to read basic type \(T.self) from value \(source)")
}
}
func read<T>(source:AnyObject?, set:T? -> ()) {
assert(false, "this is not called")
if let t:T? = source as? T? {
println("optional: read optional type: \(T.self) from value \(source)")
}
else {
println("failed to read optional type \(T.self) from value \(source)")
}
}
var m = Model()
println(m)
let raw: AnyObject? = d["a"]
struct Property<T> {
typealias V = T
var get:() -> T
var set:T -> ()
func doRead(d:[String:AnyObject]) {
read(d["a"], set)
}
}
let b = Property(get: { m.basic }, set: { v in m.basic = v })
b.doRead(d)
let o = Property(get: { m.opt }, set: { v in m.opt = v })
o.doRead(d)
Per the comment inline, I expected the second overload to be used for optional types, but it is not. Am I missing something?
Edit
Note that the compiler is inferring the optional / non optional type from the property construct - it knows that the closure takes a optional, it just doesn't select the overload. I have restored some of my original logging code above, and the output is:
basic: read type: Swift.String from value Optional(foo!)
failed to read basic type Swift.Optional from value Optional(foo!)
From my usage of Swift, I see that the compiler prefers non-optionals over optionals. The operation:
let o = Property(set: { v in m.opt = v })
Is legal even when v is a non-optional, and therefore the compiler assumes as such.
This is a good question, and I assume a lot of other questions like this will be answered soon when Swift is made open-source.
Why does this code compile (in Playground):
func text (f: String -> Void) {
f("text")
}
func foo(s: String) {
countElements(s)
}
text() {
s in
foo(s)
}
And this one doesn't:
func text (f: String -> Void) {
f("text")
}
func foo(s: String) {
countElements(s)
}
text() {
s in
countElements(s)
}
With error message:
Cannot convert the expression's type '(($T3) -> ($T3) -> $T2) -> (($T3) -> $T2) -> $T2' to type '_BuiltinIntegerLiteralConvertible'
I can tell that there is something with return type, kinda Swift thinks that I want to return int but I just want to print it
The second version of the code works if you add an explicit return statement:
text() {
s in countElements(s)
return
}
The reason for that to happens is that it uses implicit return, being a single statement closure, so it tries uses the return value of countElements, which doesn't match with the expected return type, Void. The explicit return fixes that.
As to why it behaves in a different way, in the former case foo implicitly returns Void, which matches the closure return type.
More info: Implicit Returns from Single-Expression Closures
This question already has answers here:
Closure with generic parameters
(2 answers)
Closed 7 months ago.
func myfunc<T>(i:T) -> T {
return i
}
is it possible to make this generic function a closure?
let myfunc = { <T>(i:T) -> T in
return i
}
this doesn't work...
No, because variables and expressions can't be generic. There are only generic functions and generic types.
To clarify: In some languages you can have types with a universal quantifier, like forall a. a -> a. But in Swift, types cannot have a universal quantifier. So expressions and values cannot be themselves generic. Function declarations and type declarations can be generic, but when you use such a generic function or an instance of such a generic type, some type (which could be a real type or a type variable) is chosen as the type argument, and thereafter the value you get is no longer itself generic.
Probably you need something like this.
Type declaration:
typealias ResultClosure<T> = (ResultCode, String?, T?) -> Void
Function declaration:
func loginUser(userName: String, password: String, resultHandler: ResultClosure<TokenModel>?)
Usage:
NetConnector.shared.loginUser(userName: userName ?? "", password: password ?? "") { (code, message, data) in
self.display?.unlockScreen()
if code == .success {
if let activeToken = data {
AppData.shared.userToken = activeToken
}
self.display?.showHome()
} else {
self.display?.showError(errorMessage: message)
}
}
As mentioned, variables in Swift cannot be generic, so creating a closure, whose generic types are specified by the caller is not possible. However, there are workarounds:
With SE-253, it is possible to make arbitrary (nominal) types callable. So instead of declaring a generic closure, we can declare a (non-generic) struct that has a generic callAsFunction method:
struct MyFunc {
func callAsFunction<T>(_ i: T) -> T {
return i
}
}
Now, we can declare a non-generic variable that we can call with a generic value:
let myFunc = MyFunc()
let x = myFunc(42) // -> Int
let y = myFunc("foo") // -> String
Note that this workaround doesn't apply to all situations, but it can be helpful in some.
I have found some alternative way , you can use Anyobject in your closure and pass any values to your method .
typealias genericCompletion<T:AnyObject> = ((Bool,T,String) -> Void)
struct Student {
var name:String = "Kishore"
var age : String = "125"
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.createAGenericReturn { (success, object, message) in
}
self.createStructGeneric { (success, student, message) in
}
}
func createAGenericReturn(callback:#escaping(genericCompletion<AnyObject>)){
callback(true,434.433 as AnyObject,"kishoreTest")
}
func createStructGeneric(callback:#escaping(genericCompletion<AnyObject>)){
callback(true,Student.init() as AnyObject,"kishoreTest")
}
}
Here you can see I mentioned Generic as Anyobject typealias genericCompletion = ((Bool,T,String) -> Void) , So you can pass any values to it .