Why does the nil-coalescing operator return an optional? - swift

I use Swift's nil-coalescing operator in a chain to print one of three values. The first two are optional, the last one is non-optional:
let optionalString: String? = nil
let optionalError: Error? = MyError.anError
let defaultString: String = "default"
print(optionalString ?? (optionalError ?? defaultString))
I was surprised to see that this code prints
Optional(MyError.anError)
to the console. I was expecting a non-optional:
MyError.anError
Why is this an optional?
The error is defined as follows:
enum MyError: Error {
case anError
}
I know that there are two implementations of the nil-coalescing operator:
func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T) rethrows -> T
and
func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T?) rethrows -> T?
According to this, ?? should return an optional (T?) only if the defaultValue is an optional as well (T?). But this is not the case:
The default value for the first ?? operator is (optionalError ?? defaultString). To evaluate this value's type, we need to evaluate the result of the second ?? operator. As defaultString is of type String and thus a non-optional, function (1) is used for the nil-coalescing operator. Hence, the result of (optionalError ?? defaultString) must be non-optional as well, which is the default value for the first ?? operator. So again, function (1) is used for the nil-coalescing operator and thus, optionalString ?? (optionalError ?? defaultString) should return a *non-*optional.
Apparently, there is a flaw in my logic, but I don't see it. Any explanation for this?

Disclaimer: I wasn't sure if I should add this as a supplement to my question or if I should post it as an answer. I decided for the latter. It's not a bullet-proof explanation, but I think it's "close enough" for many who might run into the same problem.
What's going wrong: The Big Picture
The two comments stating that the code provided doesn't compile for the commentators pushed me in the right direction:
I copied the code in a blank playground and ran it. For me, it did compile, but it also showed a warning which it didn't show before (because for some reason, Auto completion and compiler warnings were broken in the original project).
The warning
Expression implicitly coerced from 'Any?' to 'Any'
tells me that the expression (optionalError ?? defaultString) is apparently evaluated as type Any?, which is an optional. The compiler then chooses the ?? operator function (1) to evaluate the entire expression which requires that its default value (optionalError ?? defaultString) is non-optional. Thus, this value is implicitly coerced from Any? to Any. And that's why Optional(MyError.anError) is printed.
Why is this going wrong?
There are two questions remaining:
Why does the compiler choose operator function (1)?
Why is (optionalError ?? defaultString) evaluated to Any??
I don't have an answer for question 1,
but my guess would be that the compiler simply assigns a higher precedence to function (1) when the parameter types don't match and it's unclear which function to use. (I'll be happy to be corrected.)
Regarding question 2:
optionalError is of type MyError? and defaultString is of type String. The signature of the ?? operator functions read:
func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T) rethrows -> T
func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T?) rethrows -> T?
So both parameters, optional and defaultValue must have the "same" generic type (only that in the first case, one parameter is an optional of that particular type and the other one is not). MyError and String are obviously not the same type. So in order for this to match the criteria of the function signature, the compiler must coerce both types to Any.
So MyError? is coerced to Any? and apparently, String is also coerced to Any? and thus, function (2) is used which evaluates (optionalError ?? defaultString)toAny?`.
That again raises the question why function (2) is used in this case which kind of contradicts my assumption for question (1), but my main take-away here is that it's simply a bad idea to use two different types with the nil-coalescing operator.
Background:
I got this code example from a textbook on RxSwift which is slightly different as it uses a generic type that is required to conform to CustomStringConvertible:
func print<T: CustomStringConvertible>(label: String, event: Event<T>) {
print(label, event.element ?? event.error ?? event)
}
What got me experimenting with this in the first place was that when I ran the code from the book it printed an optional whereas the book claimed that it would print a non-optional.

Related

"Value of optional type 'Set<String>?' must be unwrapped", but I didn't ask for an optional

Xcode complains "Value of optional type 'Set?' must be unwrapped to refer to member 'contains' of wrapped base type 'Set'"
Here's the function:
func talks_to (_ dialog_dict: Dictionary<String, Set<String>>, one: String, two: String) -> Bool {
return dialog_dict[one].contains(two)
}
This is a nested function, meant only to make logic clearer, and the parameters are guaranteed to be non-nil by the outer code. How do I get swift to understand this?
Any time you fetch an item from a dictionary using subscripting, the result is an Optional because the key you use might not be found. Sh_Khan gave you a nice elegant solution: (voted)
return dialog_dict[one]?.contains(two) == true
That works because nil does not equal true, but the compiler will unwrap it and check the value inside to see if it equals true if it's not nil. So if the result of dialog_dict[one] is nil or false, it does not equal true. Only if dialog_dict contains a value for the key one and that value is true does the expression return true.
Make it
return dialog_dict[one]?.contains(two) == true
or
return dialog_dict[one]!.contains(two)
this dialog_dict[one] returns optional

Ambiguous use of operator '??'

This article shows: ?? is very time-consuming, and the test found it to be true. So I want to optimize this:
#if DEBUG
public func ?? <T>(left: T?, right: T) -> T {
guard let value = left else {
return right
}
return value
}
#endif
BUT
string = string ?? ""
ERROR: Ambiguous use of operator '??'
The article you link to does not describe how the nil coalescing operator is "time consuming", but states the simple fact that a compound expression of two nil coalescing operator calls as well as other evaluations has a significantly longer build time than if we break down this compound expressions into smaller parts, especially if the former contains lazy evaluations at some point (which is the case e.g. for the evaluation of the rhs of the ?? operator). By breaking down complex expression we help the compiler out; Swift has been known to have some difficulty compiling complex compound statements, so this is expected. This, however, should generally not affect runtime performance, given that you build your implementation for release mode.
By overloading the implementation of the ?? operator during debug with a non-lazy evaluation of the lhs while still using long compound statements shouldn't fully redeem the issue described in the previous clause. If compile time is really an issue for you, use the same approach as the author of the article; break down your complex expressions into several smaller ones, in so doing some of the work of the compiler yourself. Refactoring with the sole purpose of decreasing compile times (which we might believe is the job of the compiler, not us) might be frustrating at times, but is an issue we (currently) has to live with when working with Swift. See e.g. the following excellent article covering the Swift compiler issues with long/complex expressions:
Exponential time complexity in the Swift type checker
W.r.t. to the ambiguity error: for reference, the official implementation of the nil coelescing operator can be found here:
#_transparent
public func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
And we may note that it has the same specificity as your own generic implementation (compare the signatures!), meaning the ambiguity error is to be expected. E.g., compare with:
// due to the '#autoclosure', these two have the
// same precedecence/specificity in the overload
// resolution of 'foo(_:)'
func foo<T>(_ obj: T) {}
func foo<T>(_ closure: #autoclosure () -> T) {}
foo("foo") // ERROR at line 9, col 1: ambiguous use of 'foo'
When you implement your ?? overload it as in your answer, typing out Any, this implementation becomes more specific than the generic one, which means it will take precedence in the overload resolution of ??. Using Any is such contexts, however, is generally a bad idea, attempting to mimic dynamic typing rather than relying on Swift's renowned static typing.
if I overloading ??,I can't use <T>...
then
#if DEBUG
public func ?? (left: Any?, right: Any) -> Any {
guard let value = left else {
return right
}
return value
}
#endif
is OK!
BUT I can't get types of return value... 😭

Optional chaining with Swift strings

With optional chaining, if I have a Swift variable
var s: String?
s might contain nil, or a String wrapped in an Optional. So, I tried this to get its length:
let count = s?.characters?.count ?? 0
However, the compiler wants this:
let count = s?.characters.count ?? 0
My understanding of optional chaining is that, once you start using ?. in a dotted expression, the rest of the properties are made optional and are typically accessed by ?., not ..
So, I dug a little further and tried this in the playground:
var s: String? = "Foo"
print(s?.characters)
// Output: Optional(Swift.String.CharacterView(_core: Swift._StringCore(_baseAddress: 0x00000001145e893f, _countAndFlags: 3, _owner: nil)))
The result indicates that s?.characters is indeed an Optional instance, indicating that s?.characters.count should be illegal.
Can someone help me understand this state of affairs?
When you say:
My understanding of optional chaining is that, once you start using ?. in a dotted expression, the rest of the properties are made optional and are typically accessed by ?., not ..
I would say that you are almost there.
It’s not that all the properties are made optional, it’s that the original call is optional, so it looks like the other properties are optional.
characters is not an optional property, and neither is count, but the value that you are calling it on is optional. If there is a value, then the characters and count properties will return a value; otherwise, nil is returned. It is because of this that the result of s?.characters.count returns an Int?.
If either of the properties were optional, then you would need to add ? to it, but, in your case, they aren’t. So you don’t.
Edited following comment
From the comment:
I still find it strange that both s?.characters.count and (s?.characters)?.count compile, but (s?.characters).count doesn't. Why is there a difference between the first and the last expression?
I’ll try and answer it here, where there is more room than in the comment field:
s?.characters.count
If s is nil, the whole expression returns nil, otherwise an Int. So the return type is Int?.
(s?.characters).count // Won’t compile
Breaking this down: if s is nil, then (s?.characters) is nil, so we can’t call count on it.
In order to call the count property on (s?.characters), the expression needs to be optionally unwrapped, i.e. written as:
(s?.characters)?.count
Edited to add further
The best I can get to explaining this is with this bit of playground code:
let s: String? = "hello"
s?.characters.count
(s?.characters)?.count
(s)?.characters.count
((s)?.characters)?.count
// s?.characters.count
func method1(s: String?) -> Int? {
guard let s = s else { return nil }
return s.characters.count
}
// (s?.characters).count
func method2(s: String?) -> Int? {
guard let c = s?.characters else { return nil }
return c.count
}
method1(s)
method2(s)
On the Swift-users mailing list, Ingo Maier was kind enough to point me to the section on optional chaining expressions in the Swift language spec, which states:
If a postfix expression that contains an optional-chaining expression is nested inside other postfix expressions, only the outermost expression returns an optional type.
It continues with the example:
var c: SomeClass?
var result: Bool? = c?.property.performAction()
This explains why the compiler wants s?.characters.count in my example above, and I consider that it answers the original question. However, as #Martin R observed in a comment, there is still a mystery as to why these two expressions are treated differently by the compiler:
s?.characters.count
(s?.characters).count
If I am reading the spec properly, the subexpression
(s?.characters)
is "nested inside" the overall postfix expression
(s?.characters).count
and thus should be treated the same as the non-parenthesized version. But that's a separate issue.
Thanks to all for the contributions!

Type inference fails when using nil-coalescing operator with two optionals

We are trying to figure whether this is a bug in Swift or us misusing generics, optionals, type inference and/or nil coalescing operator.
Our framework contains some code for parsing dictionaries into models and we've hit a problem with optional properties with default values.
We have a protocol SomeProtocol and two generic functions defined in a protocol extension:
mapped<T>(...) -> T?
mapped<T : SomeProtocol>(...) -> T?
Our structs and classes adhere to this protocol and then parse their properties inside an init function required by the protocol.
Inside the init(...) function we try to set a value of the property someNumber like this:
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
The dictionary of course contains the actual value for key someNumber. However, this will always fail and the actual value will never get returned from the mapped() function.
Either commenting out the second generic function or force downcasting the value on the rhs of the assignment will fix this issue, but we think this should work the way it currently is written.
Below is a complete code snippet demonstrating the issue, along with two options that (temporarily) fix the issue labeled OPTION 1 and OPTION 2 in the code:
import Foundation
// Some protocol
protocol SomeProtocol {
init(dictionary: NSDictionary?)
}
extension SomeProtocol {
func mapped<T>(dictionary: NSDictionary?, key: String) -> T? {
guard let dictionary = dictionary else {
return nil
}
let source = dictionary[key]
switch source {
case is T:
return source as? T
default:
break
}
return nil
}
// ---
// OPTION 1: Commenting out this makes it work
// ---
func mapped<T where T:SomeProtocol>(dictionary: NSDictionary?, key: String) -> T? {
return nil
}
}
// Some struct
struct SomeStruct {
var someNumber: Double? = 0.0
}
extension SomeStruct: SomeProtocol {
init(dictionary: NSDictionary?) {
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
// OPTION 2: Writing this makes it work
// someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber!
}
}
// Test code
let test = SomeStruct(dictionary: NSDictionary(object: 1234.4567, forKey: "someNumber"))
if test.someNumber == 1234.4567 {
print("success \(test.someNumber!)")
} else {
print("failure \(test.someNumber)")
}
Please note, that this is an example which misses the actual implementations of the mapped functions, but the outcome is identical and for the sake of this question the code should be sufficient.
EDIT: I had reported this issue a while back and now it was marked as fixed, so hopefully this shouldn't happen anymore in Swift 3.
https://bugs.swift.org/browse/SR-574
You've given the compiler too many options, and it's picking the wrong one (at least not the one you wanted). The problem is that every T can be trivially elevated to T?, including T? (elevated to T??).
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
Wow. Such types. So Optional. :D
So how does Swift begin to figure this thing out. Well, someNumber is Double?, so it tries to turn this into:
Double? = Double?? ?? Double?
Does that work? Let's look for a generic mapped, starting at the most specific.
func mapped<T where T:SomeProtocol>(dictionary: NSDictionary?, key: String) -> T? {
To make this work, T has to be Double?. Is Double?:SomeProtocol? Nope. Moving on.
func mapped<T>(dictionary: NSDictionary?, key: String) -> T? {
Does this work? Sure! T can be Double? We return Double?? and everything resolves.
So why does this one work?
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber!
This resolves to:
Double? = Optional(Double? ?? Double)
And then things work the way you think they're supposed to.
Be careful with so many Optionals. Does someNumber really have to be Optional? Should any of these things throw? (I'm not suggesting throw is a general work-around for Optional problems, but at least this problem gives you a moment to consider if this is really an error condition.)
It is almost always a bad idea to type-parameterize exclusively on the return value in Swift the way mapped does. This tends to be a real mess in Swift (or any generic language that has lots of type inference, but it really blows up in Swift when there are Optionals involved). Type parameters should generally appear in the arguments. You'll see the problem if you try something like:
let x = test.mapped(...)
It won't be able to infer the type of x. This isn't an anti-pattern, and sometimes the hassle is worth it (and in fairness, the problem you're solving may be one of those cases), but avoid it if you can.
But it's the Optionals that are killing you.
EDIT: Dominik asks a very good question about why this behaves differently when the constrained version of mapped is removed. I don't know. Obviously the type matching engine checks for valid types in a little different order depending on how many ways mapped is generic. You can see this by adding print(T.self) to mapped<T>. That might be considered a bug in the compiler.

String(x) puts "optional" in the output

I'm writing a little program that reads and writes text files into an NSTableView. I had the reading working fine, and then moved onto the writing. And I got...
FR Optional(0) Optional(0) Optional(0) Optional(0) Optional(46.29) Optional(0)
I understand why this is happening: the values are NSNumbers in a dictionary, so they are, by definition, optional. But obviously this is not useful output.
Is there an easy way to output the value without the Optional and any similar bumpf?
The reason why you see Optional(n) is because you're printing the optional without unwrapping.
I suggest you re-read the optionals chapter in the Apple book to get a better grasp at why this is happening to you.
The short version is, an Optional is a type, in fact if you look at the Swift source code, you will find that's it's just an Enum!
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: ())
}
So if your values are Optionals, you have to unwrap them to see their values.
Take a look at this code and try to guess the output:
var code: String? = "hello"
if let code = code where code == "hello" {
print(code)
}
var upperCase = code?.uppercaseString
print(upperCase)
Output:
Did you figure it out?
It looks like this:
hello
Optional("HELLO")
Why does the first hello print ok?
Because it's being unwrapped in the if let statement.
But the second one, upperCase is never unwrapped, so an Optional will remain optional (unless unwrapped). code?.uppercaseString returns a new Optional. By printing it directly, we get what you see.
If you want to extract the value the optional is holding you have two operators. ? and !.
The first one is usually preferred, but if you're sure that the value is ok, you can use force the unwrap by using !, so you could do
print(uppercase!)
Careful tho, because if upperCase happens to be nil, you'd get a runtime crash.
If the values you write are held in an (optional) array, then .flatMap, prior to printing, will do the trick for you
// myOptionalDoubles : [Double?]
myOptionalDoublesForWriting = myOptionalDoubles.flatMap { $0 }
Using .flatMap like this, you unwrap any non-nil values in the array myOptionalDoubles, and return an array myOptionalDoublesForWriting of type [Double] (non-optional). Any nil entries in myOptionalDoubles will not follow to myOptionalDoublesForWriting.
If you don't want to lose information about optional entries, you can use .map instead:
// myOptionalDoubles : [Double?]
var myOptionalDoublesForWriting = myOptionalDoubles.map { $0 ?? 0.0 }
In this case, you make use of the nil coalescing operator to either unwrap each (non-nil) array entry, or, if it's nil, give it value 0.0. As above, the mapped to array myOptionalDoublesForWriting will be of non-optional type [Double].