'Cannot convert the expression's type' with optional in closure body - swift

I have come across (most definitely) a feature that I don't quite understand. I have a closure, that takes in a Float and has no return value, aka (number: Float) -> Void. In that closure, I perform a call on optional value, not forcing its unwrapping, because I like the behavior since the optional is a delegate (= if it's nil, don't do anything).
But when I do that, I get an error:
Cannot convert the expression's type '...' to type Float.
Interestingly enough, when I simply add println(), the error disappears. I have simplified my case to tiny little example for illustration:
var optional: [String : Int]?
let closure: (number: Int) -> Void = { (number) -> Void in
optional?.updateValue(number, forKey: "key")
//println() <-- when this gets uncommented, error disappears
}
My bet would be that the compiler maybe doesn't like that in some cases I'm not handling the float number, but since I am not returning the value then it should just disappear right? What am I missing?

An expression containing a single expression is inferred to return that result, hence:
let closure: (number: Int) -> Void = { (number) -> Void in
optional?.updateValue(number, forKey: "key")
}
is equivalent to:
let closure: (number: Int) -> Void = { (number) -> Void in
return optional?.updateValue(number, forKey: "key")
}
You now have conflicting return types between Void and Int? (remember, updateValue returns the old value)
Splitting it up with an explicit return clarifies the inferred typing.
let closure: (number: Int) -> Void = { (number) -> Void in
optional?.updateValue(number, forKey: "key")
return
}

I think your closure won't like returning nil because Void can't be converted to nil.
If you do that in a playground:
var n: Void = ()
n = nil
You'll get this error:
error: type 'Void' does not conform to protocol 'NilLiteralConvertible'

Related

How does typecasting/polymorphism work with this nested, closure type in Swift?

I know that (Int) -> Void can't be typecasted to (Any) -> Void:
let intHandler: (Int) -> Void = { i in
print(i)
}
var anyHandler: (Any) -> Void = intHandler <<<< ERROR
This gives:
error: cannot convert value of type '(Int) -> Void' to specified type
'(Any) -> Void'
Question: But I don't know why this work?
let intResolver: ((Int) -> Void) -> Void = { f in
f(5)
}
let stringResolver: ((String) -> Void) -> Void = { f in
f("wth")
}
var anyResolver: ((Any) -> Void) -> Void = intResolver
I messed around with the return type and it still works...:
let intResolver: ((Int) -> Void) -> String = { f in
f(5)
return "I want to return some string here."
}
let stringResolver: ((String) -> Void) -> Void = { f in
f("wth")
}
var anyResolver: ((Any) -> Void) -> Any = intResolver (or stringResolver)
Sorry if this is asked before. I couldn't find this kind of question yet, maybe I don't know the keyword here.
Please enlighten me!
If you want to try: https://iswift.org/playground?wZgwi3&v=3
It's all about variance and Swift closures.
Swift is covariant in respect to closure return type, and contra-variant in respect to its arguments. This makes closures having the same return type or a more specific one, and same arguments or less specific, to be compatible.
Thus (Arg1) -> Res1 can be assigned to (Arg2) -> Res2 if Res1: Res2 and Arg2: Arg1.
To express this, let's tweak a little bit the first closure:
import Foundation
let nsErrorHandler: (CustomStringConvertible) -> NSError = { _ in
return NSError(domain: "", code: 0, userInfo: nil)
}
var anyHandler: (Int) -> Error = nsErrorHandler
The above code works because Int conforms to CustomStringConvertible, while NSError conforms to Error. Any would've also work instead of Error as it's even more generic.
Now that we established that, let's see what happens in your two blocks of code.
The first block tries to assign a more specific argument closure to a less specific one, and this doesn't follow the variance rules, thus it doesn't compile.
How about the second block of code? We are in a similar scenario as in the first block: closures with one argument.
we know that String, or Void, is more specific that Any, so we can use it as return value
(Int) -> Void is more specific than (Any) -> Void (closure variance rules), so we can use it as argument
The closure variance is respected, thus intResolver and stringResolver are a compatible match for anyResolver. This sounds a little bit counter-intuitive, but still the compile rules are followed, and this allows the assignment.
Things complicate however if we want to use closures as generic arguments, the variance rules no longer apply, and this due to the fact that Swift generics (with few exceptions) are invariant in respect to their type: MyGenericType<B> can't be assigned to MyGenericType<A> even if B: A. The exceptions are standard library structs, like Optional and Array.
First, let's consider exactly why your first example is illegal:
let intHandler: (Int) -> Void = { i in
print(i)
}
var anyHandler: (Any) -> Void = intHandler
// error: Cannot convert value of type '(Int) -> Void' to specified type '(Any) -> Void'
An (Any) -> Void is a function that can deal with any input; an (Int) -> Void is a function that can only deal with Int input. Therefore it follows that we cannot treat an Int-taking function as a function that can deal with anything, because it can't. What if we called anyHandler with a String?
What about the other way around? This is legal:
let anyHandler: (Any) -> Void = { i in
print(i)
}
var intHandler: (Int) -> Void = anyHandler
Why? Because we can treat a function that deals with anything as a function that can deal with Int, because if it can deal with anything, by definition it must be able to deal with Int.
So we've established that we can treat an (Any) -> Void as an (Int) -> Void. Let's look at your second example:
let intResolver: ((Int) -> Void) -> Void = { f in
f(5)
}
var anyResolver: ((Any) -> Void) -> Void = intResolver
Why can we treat a ((Int) -> Void) -> Void as an ((Any) -> Void) -> Void? In other words, why when calling anyResolver can we forward an (Any) -> Void argument onto an (Int) -> Void parameter? Well, as we've already found out, we can treat an (Any) -> Void as an (Int) -> Void, thus it's legal.
The same logic applies for your example with ((String) -> Void) -> Void:
let stringResolver: ((String) -> Void) -> Void = { f in
f("wth")
}
var anyResolver: ((Any) -> Void) -> Void = stringResolver
When calling anyResolver, we can pass an (Any) -> Void to it, which then gets passed onto stringResolver which takes a (String) -> Void. And a function that can deal with anything is also a function that deals with strings, thus it's legal.
Playing about with the return types works:
let intResolver: ((Int) -> Void) -> String = { f in
f(5)
return "I want to return some string here."
}
var anyResolver: ((Any) -> Void) -> Any = intResolver
Because intResolver says it returns a String, and anyResolver says it returns Any; well a string is Any, so it's legal.

Understanding why this Swift tuple assignment isn't allowed

The following code is fine:
func intTest() -> Int? {
var res : Int
res = 5
return res
}
There is no problem returning a non-optional Int from a method with a return type of optional Int.
Now lets see what happens when the return value is a tuple of optional values:
func tupleTest() -> (Int?, Int?) {
var res : (Int, Int)
res = (5, 5)
return res
}
The return res line results in the error:
error: cannot express tuple conversion '(Int, Int)' to '(Int?, Int?)' (aka '(Optional, Optional)')
Why does Swift not allow this?
I certainly understand why this would be an error in the other direction (optional to non-optional) but why can't a tuple accept a non-optional value in the place of an optional when a non-tuple works fine?
I've seen Swift tuple to Optional assignment but that doesn't cover why you can't do the assignment, it just covers how to solve it.
The reason that's happening is because of a type mismatch. Consider the following case:
let myClosure: (Int) -> ()
let myOtherClosure: (Int?) -> ()
The type of myClosure is (Int) -> () while myOtherClosure is of type (Int?) -> () which makes them fundamentally different types, despite the similarity of the parameters. When Swift is looking at these two constants, it's evaluating the type as a whole, not the individual pieces. The same is happening with your tuple; it's looking at the tuple type signature as a whole unit, not breaking down the parameters and recognizing that they're non-optional versions of the same type.
Converting from Int to Int? works because they're the same type, one is just an optional. Going from (Int, Int) to (Int?, Int?) doesn't because the parameters of the tuple are different therefore causing the overall type to be different, hence your error.
Taking a look at one of your examples:
func tupleTest() -> (Int?, Int?) {
let first: Int = 1
let second: Int = 2
let res: (Int?, Int?) = (first, second)
return res
}
This works because even though the values are non-optional integers, the tuple type is marked as (Int?, Int?) whereas:
func tupleTest() -> (Int?, Int?) {
let first: Int = 1
let second: Int = 2
let res = (first, second)
return res
}
doesn't compile because now res is of type (Int, Int). I'm not an expert on the Swift compiler but my guess is that the way the type system works is it doesn't deconstruct each individual part of a function or a tuple and recognize that the corresponding return parameter is the same type, just an optional.

What is the syntax for a closure argument in swift

In Swift headers, the isSeparator: argument accepts a closure
public func split(maxSplit: Int = default, allowEmptySlices: Bool = default, #noescape isSeparator: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.SubSequence]
But in the documentation, it lists closure syntax differently
{ (parameters) -> return type in
statements
}
How are you supposed to know that (Self.Generator.Element) throws -> Bool rethrows refers to a closure / requires a closure? Are there other ways that the headers/docs might list argument as meaning a closure?
The "thing" giving away that this is a closure is the ->. The full type is
(Self.Generator.Element) throws -> Bool
It means that the closure takes a variable of type Self.Generator.Element and has to return a Bool upon some calculation based on the input. It may additionally throw some error while doing so - that is what the throws is for.
What you then write
{ (parameters) -> return type in
statements
}
would be an actual implementation, a value of some generic closure type.
The type of a closure is for example (someInt:Int, someDouble:Double) -> String:
var a : ((someInt:Int, someDouble:Double) -> String)
Once again the thing giving away that a is actually a closure is the -> in the type declaration.
Then you assign something to a via some code snippet following your second code block:
a = { (integer, floating) -> String in
return "\(integer) \(floating)"
}
You can tell by the argument's type. Everything in Swift has a type, including functions and closures.
For example, this function...
func add(a: Int, to b: Int) -> Int { return a + b }
...has type (Int, Int) -> Int. (It takes two Ints as parameters, and returns an Int.)
And this closure...
let identity: Int -> Int = { $0 }
...has type Int -> Int.
Every function and closure has a type, and in the type signature there is always a -> that separates the parameters from the return value. So anytime you see a parameter (like isSeparator) that has a -> in it, you know that the parameter expects a closure.
the isSeparator definition means (Self.Generator.Element) throws -> Bool that you will be given an Element and you should return a Bool. When you will call split, you then can do the following :
[1,2,3].split(…, isSeparator : { element -> Bool in
return false
})
This is a pure silly example but that illustrates the second part of your question

Using Swift's optional binding to get NSData's bytes directly?

I have the following code, assuming data is of type NSData?:
if let myData = data {
let bytes = UnsafePointer<UInt8>(myData.bytes)
...
}
How do I reduce this to a single statement, such as:
if let bytes = UnsafePointer<UInt8>?(data?.bytes) {
...
}
The above gives an error of: Cannot invoke initializer for type 'UnsafePointer<UInt8>?' with an argument list of type '(UnsafePointer<Void>?)'
Similarly as in Getting the count of an optional array as a string, or nil, you can use the map()
method of Optional:
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`.
#warn_unused_result
#rethrows public func map<U>(#noescape f: (Wrapped) throws -> U) rethrows -> U?
In your case:
if let bytes = (data?.bytes).map({ UnsafePointer<UInt8>($0) }) {
}
(data?.bytes) uses optional chaining and has the type
UnsafePointer<Void>?. The map function is used to convert that
to UnsafePointer<UInt8>?, which is finally unwrapped with the
optional binding.

Shorthand for wrapping a swift variable in an optional?

Swift allows us to use the shorthand notation str! to unwrap an optional. But what if we want to do the opposite?
Say I have a variable:
var str = String() // String
Is there any shorthand notation to convert this to an optional (i.e. String? or String!)?
(E.g. I want to do something like var strOptional = ?(str).)
Alternatively, if there is no shorthand for this notation, how can I convert it to an optional without explicitly mentioning its type (e.g. I don't want to mention String).
In other words, I know that I can wrap a variable as an optional with any of these methods:
var strOptional = str as String?
var strOptional: String? = str
var strOptional = String?(str)
... but in each case, I must explicitly write String.
I would rather write something like: var strOptional = str as typeof?(str), if there is no shorthand syntax. (The advantage is that if the variable's type is frequently changed in the code base, it would be one less place to update.)
As far as a real world example of where this would be useful, imagine I want to use an AVCaptureDevice and I use the following code:
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
device.lockForConfiguration(nil)
lockForConfiguration() will crash at runtime on a device that has no video camera, and the compiler won't warn me about it. The reason is that defaultDeviceWithMediaType may return nil according to the documentation[1], yet it is defined to return a AVCaptureDevice!.
To fix a faulty API like this, it would be nice to do something like:
let device = ?(AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo))
... to get a AVCaptureDevice?, and have the compiler catch any mistakes I might make.
Currently, I must resort to the more verbose:
let device: AVCaptureDevice? = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
Another example:
In this case, I want to give a default value to my variable that is a string, but later on, I may want to assign it a nil value.
var myString = "Hi"
// ...
if (someCondition()) {
myString = nil // Syntax error: myString is String
}
Currently I have to resort to var myString: String? = "Hi" but something like var myString = ?("Hi") would be less verbose.
[1] If you open AVCaptureDevice.h, you will see the following documentation about the return value: "The default device with the given media type, or nil if no device with that media type exists."
Optional is just an enum in swift, so you can do: Optional(str)
From the swift interface:
/// A type that can represent either a `Wrapped` value or `nil`, the absence
/// of a value.
public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
/// Construct a `nil` instance.
public init()
/// Construct a non-`nil` instance that stores `some`.
public init(_ some: Wrapped)
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`.
#warn_unused_result
public func map<U>(#noescape f: (Wrapped) throws -> U) rethrows -> U?
/// Returns `nil` if `self` is `nil`, `f(self!)` otherwise.
#warn_unused_result
public func flatMap<U>(#noescape f: (Wrapped) throws -> U?) rethrows -> U?
/// Create an instance initialized with `nil`.
public init(nilLiteral: ())
}
To wrap up a variable you could use operator overloading and generic functions. For example:
prefix operator ??? {}
prefix func ??? <T> (x: T) -> T? {
return Optional(x)
}
To relate this to your second example, you would do the following:
var myString = ???"Hi" // Optional("Hi")
if someCondition() {
myString = nil
}
In the lighthearted spirit that, as I understand, the question was posed, you can define a postfix operator that uses one character less than your ideal solution (a pair of parens and a question mark):
postfix operator =? {}
postfix func =? <T> (rhs: T) -> T? { return rhs }
postfix func =? <T> (rhs: T!) -> T? { return rhs ?? nil }
var x = 3=?
x is Int? //--> true
var imp: Int! = 3
var opt = imp=?
opt is Int? //--> true
As to Apple's APIs you mention, since they already return an optional, albeit an implicitly unwrapped optional, you could use the nil coalescing operator ?? to convert it to a plain optional:
let y: Int! = 3 // posing for a rogue API
y is Int? //--> false
let z = y ?? nil
z is Int? //--> true
Perhaps a sligtly more interesting use of a dodgy operator is a higher order operator function that lifts T -> Us into T? -> U?s...
func opt <T, U> (f: T -> U) -> T? -> U? { // we'll implement this as an operator
return { $0.map(f) }
}
postfix operator ->? {}
postfix func ->? <T, U> (f: T -> U) -> T? -> U? {
return { $0.map(f) }
}
Now, let's use it:
let square: Int -> Int = { $0 * $0 }
let i: Int? = 3
square->? (i)
Which is equivalent to:
opt(square)(i)
Which is equivalent to (but potentially a little more versatile than):
i.map(square)
This all makes much more sense when used along with the pipe forward operator:
infix operator |> { associativity left precedence 89 }
func |> <A, B>(a: A, f: A -> B) -> B {
return f(a)
}
Then you can do:
i |> opt(square)
or
i |> square->?
Or we can conflate these into an optional pipe forward, which can take care of implicitly unwrapped optionals too:
infix operator ?> { associativity left precedence 89 }
func ?> <T, U> (lhs: T?, rhs: T -> U) -> U? {
return lhs.map(rhs)
}
let im: Int! = 5
let op: Int? = 5
im ?> square |> debugPrintln //--> Optional(25)
op ?> square |> debugPrintln //--> Optional(25)
Which is equivalent to:
debugPrintln(op.map(square))