Issue
func biggerOne(_ a : Int, _ b : Int) -> Int? {
if a == b {
return nil
} else if a > b {
return a
} else {
return b
}
}
var someClosure : (Int, Int) -> Int? = biggerOne(_:_:)
// Not working
someClosure = { (left : Int, right : Int) in
someClosure(left , right)
}
print(someClosure(2,3)!)
// Working
someClosure = { [someClosure] (left : Int, right : Int) in
someClosure(left , right)
}
print(someClosure(2,3)!)
I knew that closure uses capture list to store values on creation so can solve the problem but why is the code above not working?
If you have any ideas, I would appreciate your help.
Solution
Without capturing, someClosure
here is simply calling itself, and then causing a stack overflow:
someClosure = { (left : Int, right : Int) in
someClosure(left , right) // this call refers to the new value of "someClosure"
}
(I’m not sure if the fact that this passes compilation is intentional.)
This is just like as if you have defined a named function like:
func someClosure(left: Int, right: Int): Int? {
someClosure(left: left, right: right)
}
On the other hand, the capture list captures the old value of someClosure
, so "someClosure
" inside the closure body refers to the captured value (i.e. the old value), and there is no infinite recursion. You can think of this as:
let captured = someClosure
someClosure = { (left : Int, right : Int) in
captured(left , right)
}
Using lldb yourExecutable
and the thread backtrace
command, you can see the many duplicated stack frames that are caused by the recursion.
(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7ff7bf6ffff8)
* frame #0: 0x00007ff822e4fa99 libswiftCore.dylib`swift_beginAccess + 41
frame #1: 0x0000000100003d87 yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 71
frame #2: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #3: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #4: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
...
frame #65515: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #65516: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #65517: 0x0000000100003baa yourExecutable`main + 218
frame #65518: 0x00000001000154fe dyld`start + 462
Answered By – Sweeper
Answer Checked By – Robin (BugsFixing Admin)