Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

swift: if-let with parallel assignment

I'm trying to make a simple if-let statement with more than one value. The if block should be executed only if all optional vars are non-nil, plus they should be assigned to the new let-vars (constants?) that live only inside the if block, just like the normal single-assignment if-let.

var a: String? = "A"
var b: String? // nil

if let (m, n) = (a, b) {
    println("m: \(m), n: \(n)")
} else {
    println("too bad")
}
// error: Bound value in a conditional binding must be of Optional type
// this of course is because the tuple itself is not an Optional
// let's try that to be sure that's the problem...

let mysteryTuple: (String?, String?)? = (a, b)
if let (m, n) = mysteryTuple {
    println("m: \(m), n: \(n)")
} else {
    println("too bad")
}
// yeah, no errors, but not the behavior I want (printed "m: A, n: nil")

// and in a different way:
if let m = a, n = b {
    println("m: \(m), n: \(n)")
} else {
    println("too bad")
}
// a couple syntax errors (even though 'let m = a, n = b'
// works on its own, outside the if statement)

Is this even possible? If not (which I'm guessing), do you think Apple will (or should) implement this in the future?

like image 669
maltalef Avatar asked Jul 18 '14 17:07

maltalef


People also ask

When to use guard vs if let?

So, use if let if you just want to unwrap some optionals, but prefer guard let if you're specifically checking that conditions are correct before continuing.

How does if let work in Swift?

The “if let” allows us to unwrap optional values safely only when there is a value, and if not, the code block will not run. Simply put, its focus is on the “true” condition when a value exists.

How to assign value in Swift?

Overview. We can assign values to multiple variables at once in a single statement in Swift. We need to wrap the variables inside a bracket and assign the values using the equal sign = . The values are also wrapped inside a bracket.


2 Answers

This is probably evident by now, but your quest for this expected functionality can end with the release of Swift 1.2.

From the swift blog: https://developer.apple.com/swift/blog/?id=22

More powerful optional unwrapping with if let — The if let construct can now unwrap multiple optionals at once, as well as include intervening boolean conditions. This lets you express conditional control flow without unnecessary nesting.

The short of it though, is that you can now do what you are asking, in addition to constraining the values with where clauses.

if let a = foo(), b = bar() {
}
like image 157
Chris Conover Avatar answered Nov 10 '22 02:11

Chris Conover


Before deciding whether it is possible or not, consider why if - let ... conditionals work with a single optional value: the reason this code compiles

if let constVar = testVar {
    ...
}

is that all optional types conform to the LogicalValue protocol, which handles the null checking of the optional value.

This explains why your trick with an optional tuple did not work either: the implementation of the LogicalValue checked if the tuple itself is non-null, ignoring its components. The logic behind Apple's decision is clear: rather than making an exception for tuples when all their element types are optional, they took the uniform approach, and treated the tuple in the same way that they treat other optional types.

Of course, implementing the logic that you are trying to implement is easy with an additional line of code:

if a != nil && b != nil {
    let (m, n) = (a!, b!)
    println("m: \(m), n: \(n)")
} else {
    println("too bad")
}
like image 9
Sergey Kalinichenko Avatar answered Nov 10 '22 01:11

Sergey Kalinichenko