[swift-users] Compiler refuses non-escaping closure calls in nested function

Ole Begemann ole at oleb.net
Mon Oct 10 05:52:03 CDT 2016


> The line "let result = closure(n)" is refused by the compiler with the
> error message "declaration over non closing parameter may allow it to
> escape".
>
> First off, while I know what an escaping or a non-escaping closure is, I
> find this error message utterly impossible to understand. To begin with,
> the sentence "non closing parameter" is meaningless to me.

The error message I'm seeing in Xcode 8.0 is "Declaration closing over 
*non-escaping* parameter 'closure' may allow it to escape", so I don't 
know where you're seeing the "non closing parameter". And "non-escaping 
parameter" does make a lot more sense, I think.

> In any case, my main function is passed a non-escaping closure. I want
> to call it from inside it, the compiler is ok with. I want also to call
> it from a nested function, but the compiler disagrees.
>
> I believe the compiler should not complain here. Did I miss anything?

I think the error message is actually quite good, given that the 
compiler apparently is taking some shortcuts to prove that a parameter 
doesn't escape.

By declaring a function that closes over the non-escaping parameter, 
you're creating a situation that *may* allow the non-escaping closure to 
escape, i.e. the compiler can't guarantee anymore that it won't escape. 
For example, you could do assign the `closureDoubled` function to a 
variable that's outside the scope of `mainFunction`:

     // Variable outside the scope of mainFunction
     var f: (Int) -> (Int) = { $0 }

     func mainFunction(closure: (Int) -> Int) -> Int {

         func closureDoubled(_ n: Int) -> Int {
             let result = closure(n)
             return 2*result
         }

         // closure would escape here
         f = closureDoubled
	...
     }

     mainFunction { $0 }
     f(5)

If this were allowed, `closure` would be able to escape. I think this 
possibility explains the error message.

Now the compiler *could* of course check for this and I think you're 
right in arguing that it *should* ideally perform more sophisticated 
checks, but since it currently seems to be taking some shortcuts in 
guaranteeing that a parameter doesn't escape, it has to disallow 
anything it can't verify as correct.

Ole


More information about the swift-users mailing list