What's the difference between if nil != optional … and if let _ = optional …

After optimization, the two approaches are probably the same.

For example, in this case, compiling both the following with swiftc -O -emit-assembly if_let.swift:

import Darwin

// using arc4random ensures -O doesn’t just
// ignore your if statement completely
let i: Int? = arc4random()%2 == 0 ? 2 : nil

if i != nil {
  println("set!")
}

vs

import Darwin

let i: Int? = arc4random()%2 == 0 ? 2 : nil

if let _ = i {
  println("set!")
}

produces identical assembly code:

    ; call to arc4random
    callq   _arc4random
    ; check if LSB == 1 
    testb   $1, %al
    ; if it is, skip the println
    je  LBB0_1
    movq    $0, __Tv6if_let1iGSqSi_(%rip)
    movb    $1, __Tv6if_let1iGSqSi_+8(%rip)
    jmp LBB0_3
LBB0_1:
    movq    $2, __Tv6if_let1iGSqSi_(%rip)
    movb    $0, __Tv6if_let1iGSqSi_+8(%rip)
    leaq    L___unnamed_1(%rip), %rax  ; address of "set!" literal
    movq    %rax, -40(%rbp)
    movq    $4, -32(%rbp)
    movq    $0, -24(%rbp)
    movq    __TMdSS@GOTPCREL(%rip), %rsi
    addq    $8, %rsi
    leaq    -40(%rbp), %rdi
    ; call println
    callq   __TFSs7printlnU__FQ_T_
LBB0_3:
    xorl    %eax, %eax
    addq    $32, %rsp
    popq    %rbx
    popq    %r14
    popq    %rbp
    retq

The if let syntax is called optional binding. It takes an optional as input and gives you back a required constant if the optional is not nil. This is intended for the common code pattern where you first check to see if a value is nil, and if it's not nil (if it has a value), you do something with it.

If the optional is nil, processing stops and the code inside the braces is skipped.

The if optional != nil syntax is simpler. It simply checks to see if the optional is nil. It skips creating a required constant for you.

The optional binding syntax is wasteful and confusing if you're not going to use the resulting value. Use the simpler if optional != nil version in that case. As nhgrif points out, it generates less code, plus your intentions are much clearer.

EDIT:

It sounds like the compiler is smart enough to not generate extra code if you write "if let" optional binding code but don't end up using the variable you bind. The main difference is in readability. Using optional binding creates the expectation that you are going to use the optional that you bind.


I personally think it looks unpleasant because you are comparing nil to your result instead of your result to nil:

if self?.checklists.itemPassingTest({ $0 === note.object }) != nil {
    …
}

Since you only want to ensure it is not nil and not use item there is no point in using let.

Tags:

Swift

Optional