Jeffery Thomas - 1 year ago 55
Swift Question

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

I need to test if an expression which returns an optional is

nil
. This seems like a no-brainer, but here is the code.

if nil != self?.checklists.itemPassingTest({ $0 === note.object }) { … }  Which, for some reason, looks unpleasant to my eye. if let item = self?.checklists.itemPassingTest({$0 === note.object }) {
…
}


Looks much better to me, but I don't actually need the item, I just need to know if one was returned. So, I used the following.

if let _ = self?.checklists.itemPassingTest({ $0 === note.object }) { … }  Am I missing something subtle here? I think if nil != optional … and if let _ = optional … are equivalent here. Update to address some concerns in the answers 1. I don't see the difference between nil != var and var != nil , although I generally use var != nil . In this case, pushing the != nil after the block gets the boolean compare of block mixed in with the boolean compare of the if. 2. The use of the Wildcard Pattern should not be all that surprising or uncommon. They are used in tuples (x, _) = (10, 20) , for-in loops for _ in 1...5 , case statements case (_, 0): , and more (NOTE: these examples were taken from The Swift Programming Language). This question is about the functional equivalency of the two forms, not about coding style choices. That conversation can be had on programmers.stackexchange.com. After all this time, Swift 2.0 makes it moot if self?.checklists.contains({$0 === note.object }) ?? false {
…
}


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