Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does this closure code throw an error when not using a capture list?

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>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
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading