1

I've been playing with optionals in swift. I make frequent use of the conditional unwrap pattern:

var myOptional: AnyObject?
if let unwrapped = myOptional {
// do stuff
}

However, on occasion I have two optional values that I only want to use if both of them are non-nil. As such, I tried to use the following syntax:

var myOptional: AnyObject?
var myOtherOptional: AnyObject?
if let unwrapped = myOptional && let otherUnwrapped = myOtherOptional? {
// do stuff
}

I've tried putting the two parts in brackets etc. but there doesn't seem to be a way to do this. Is there a good reason why I shouldn't be able to do it? Obviously I can just embed one statement in the other but I would prefer to put it all on one line.

public static void
  • 1,153
  • 11
  • 20
  • 1
    May be it isn't supported without a reason :) – BaSha Jan 27 '15 at 13:05
  • I'm pretty sure this has been asked here already. Just nest the unwraps. Swift has some nice concepts, but it lacks real world practice. So I go with @BaSha – qwerty_so Jan 27 '15 at 13:13
  • 1
    There's a nice discussion here: [http://stackoverflow.com/questions/24548999/unwrapping-multiple-optionals-in-if-statement](http://stackoverflow.com/questions/24548999/unwrapping-multiple-optionals-in-if-statement). Have a look at the `unwrap` helper function. – Para Jan 27 '15 at 13:14
  • Ah great :) What a bad mistake to use a double key word `if let` :-( – qwerty_so Jan 27 '15 at 13:17

4 Answers4

6

Starting with Swift 1.2 you can unwrap multiple optionals and conditions.

The “if let” construct has been expanded to allow testing multiple optionals and guarding conditions in a single if (or while) statement using syntax similar to generic constraints: if let a = foo(), b = bar() where a < b, let c = baz() { } This allows you to test multiple optionals and include intervening boolean conditions, without introducing undesirable nesting (i.e., to avoid the “pyramid of doom”).

Marius Fanu
  • 6,589
  • 1
  • 17
  • 19
5

Because the language doesn't support it.

In the document:

The value of any condition in an if statement must have a type that conforms to the BooleanType protocol. The condition can also be an optional binding declaration, as discussed in Optional Binding.

The condition must be an "expression of BooleanType" or an "optional binding declaration". And "optional binding declaration" is not an "expression" so you can't join with &&.

Instead, you can do that with switch:

switch (myOptional, myOtherOptional) {
case let (.Some(unwrapped), .Some(otherUnwrapped)):
    // do stuff
    println("\(unwrapped), \(otherUnwrapped)")
default:
    break
}
rintaro
  • 51,423
  • 14
  • 131
  • 139
  • 1
    This technique was also demonstrated here http://stackoverflow.com/a/25048307/1187415 and here http://stackoverflow.com/a/24592684/1187415. – Martin R Jan 27 '15 at 13:34
0

The only way is to nest if statements. I think this is because apple implemented it as syntactic sugar. So the pre compiler converts

var myOptional: AnyObject?
if let unwrapped = myOptional {
    // do stuff
}

into

var myOptional: AnyObject?
if myOptional != nil {
    let unwrapped = myOptional
    // do stuff
}

You can of course do this by yourself in a single if, but this will make your code only a little prettier. On the downside, you won't know which one caused the crash while debugging.

For more information see the documentation

Ramzi Khahil
  • 4,932
  • 4
  • 35
  • 69
  • *"So the pre compiler converts ... to ..."* – I don't think so (and I don't think that the Swift compiler even uses a pre-compiler). In fact the two code blocks are not 100% equivalent in terms of thread-safety. – Martin R Jan 27 '15 at 13:22
  • @MartinR Well as I said "I think", sadly I have found nothing to support or weaken this claim. Anyway, it may be done as part of the compilation process. This can easily be done when you have an AST (Abstract Syntax Tree). But honestly I have no read idea what apple is doing there, I'm only guessing. – Ramzi Khahil Jan 27 '15 at 13:33
  • @MartinR as to thread safety, if you write something in one line, it does not mean it will be thread safe. So the first option still may be not thread safe. – Ramzi Khahil Jan 27 '15 at 13:35
-1
    var myOptional: AnyObject?
    var myOtherOptional: AnyObject?
    let unwrapped: AnyObject? = myOptional,  otherUnwrapped: AnyObject? = myOtherOptional?
    if (unwrapped != nil && otherUnwrapped != nil) {
       // Do Stuff 
    }

This is another way you could do it. Swift is looking better day by day

LukeTerzich
  • 555
  • 1
  • 4
  • 17