The Optional Truth

Didn't swift 1 have a similar unwrapping feature for Bool? instances that was removed because it was confusing to know if it was checking for true or nil. I believe it was checking for nil...

I don't think so. BooleanType still existed, allowing custom types to define how they're interpreted in a Boolean context, but conditional conformances didn't exist yet, so it wouldn't have been possible to write extension Optional: BooleanType where Self.Wrapped: BooleanType {...

You could've written something that just tested for the presence of any value, and some people argued that that was the right behavior for Optional. But it was confusing for a variety of reasons, not least being that it would handle this Bool? case by producing true even for .some(false).

I don't think the suggestion here is that we should generally support using a Bool? as a condition; it's that we should specifically support using the result of a ?-chain where the chain yields a Bool as a condition, which is essentially equivalent to treating the rest of the if-clause as if it was still part of the chain. That seems more reasonable to me, but it is still a special case.

While conditional conformance didn't exist the compiler synthesized some of this for you back in the earliest versions of swift. It was one of the first things removed.

If you look here under the 2014-08-18 section you find:

Optionals no longer implicitly evaluate to true when they have a value and false when they do not, to avoid confusion when working with optional Bool values. Instead, make an explicit check against nil with the == or != operators to find out if an optional contains a value.

8 Likes

Interesting. That seems a lot less reasonable to me because it's a weirder special case that would behave unlike anything else in Swift and be very far away from anything you can actually express in your own code. Or is someone suggesting that should there be a parameter attribute for @optionalChainingResultingInOptionalBoolConvertsToBool

I was just restating what I believed to be the proposal.

I don't think allowing a generic Bool? to be used as a condition is a good idea at all.

12 Likes

FWIW, on my team we recommend using nil-coalescing, rather than equality, for checks like this.

For example, instead of:

if one?.isImportant == true {
}

we would write:

if one?.isImportant ?? false {
}

Both are functionally equivalent, but the latter has a nice benefit: If future refactoring results in the left side becoming non-optional, the compiler will generate a warning, like:

if one.isImportant ?? false {
//                ^^^^^^^^^ WARNING: Left side of nil coalescing operator '??' has 
//                          non-optional type 'Bool', so the right side is never used
}
13 Likes

I agree. Swift 1.0 beta 1 had optionals conforming to "LogicValue", and it caused no end of confusion.

-Chris

5 Likes

@Chris_Lattner3 I think the idea of using a protocol to expose an if statement's boolean check as a configuration point in the language should be revisited. It makes a lot of sense now, in the context of dynamic language interop, to want to say if someBoolPyValue {...

2 Likes

If we had generic protocols, we could do the C++ thing and just have types that implicitly convert to bool.

extension PyValue: ImplicitlyConvertibleTo<Bool> {
    public func convert() -> Bool {
        // However you convert a PyValue to bool.
    }
}

Or, in the other direction...

extension Bool: ImplicitlyConvertibleFrom<PyValue> {
    public init(_ value: PyValue) {
        // However you convert a PyValue to bool.
    }
}

ImplicitlyConvertibleFrom<T> would probably be easier to implement, but who knows.

1 Like

I don't think dynamic language interop means that Swift has to allow you to write JavaScript code using Swift syntax. Explicitly checking the truthiness of the value is fine.

8 Likes