Ways to unwrap-mutate-wrap optionals

Using if let someOptional { } is convenient, but it also
means that the local unwrapped variable (or constant) makes
the original optional, having the same name, inaccessible
(a.k.a. variable shadowing).

Here are some possible solutions to unwrap-mutate-wrap
optionals with if let/var without needing to come up with
a new name for the unwrapped local variable.

Since the $ sign can be used in variable names, the following
approach is currently possible. You still have to write the
variable name twice, though.

var n: Int? = 1

if let n$ = n { n = n$ + 2 }

print(n) // 3

Three prospective solutions follow here below.

(1) I pitched this some time ago, where pre refers to a previous
variable outside of the inner scope.

var n: Int? = 1

if let n { pre.n = n + 2 }

print(n) // 3

Mutating more than one optional is possible:

var n1: Int? = 1
var n2: Int? = 2

if let n1, let n2 { pre.n1 = n1 + 2; pre.n2 = n1 + n2 }

print(n1, n2) // both are 3

Note that pre could be used generally to access a variable with
the same name, but being defined outside of the local scope:

let i: Int = 5

if condition {
    let i: Int = 2
    
    print(pre.i + i) // 7
}

(2) Use assignment from if statement. The rule would be that if
there is only one statement between braces, the word return
can be left out. If the optional is nil, no assignment takes place.

var n: Int? = 1

n = if let n { n + 2 }

print(n) // 3

If there is more than one statement between the braces, my
suggestion would be to use the word use instead of return:

var n: Int? = 1

n = if let n { doChore(); use n + 2 }

print(n) // 3

(3) Differentiate (slightly less clear than the other solutions
since it relies on assumptions).

Use if let, knowing that the optional is the one that it is
possible to assign to.

var n: Int? = 1

if let n { n = n + 2 }

print(n) // 3

With if var, the local variable is the one that it is primarily
possible to assign a new value to. Then, if the optional should
be assigned to, do like this:

var n: Int? = 1

if var n { n += 2; n = n }

print(n) // 3

Other solutions are welcome.

Just use map:

n = n.map { $0 + 2 }
4 Likes

Didn't know about that syntax, that is better.

In Swift 5.9, this is almost possible like this:

var n: Int? = 1

n = if let n { n + 2 } else { nil }

print(n) // Actually prints 'Optional(3)'

Great replies – much appreciated!

P.S. An alternative to the $ sign (that I introduced in my first example),
could be to append _u, where u stands for unwrapped.

var n: Int? = 1

if let n_u = n { n = n_u + 2 }

print(n) // 3

I don't know which one is better.