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

Jean-Denis Muys jdmuys at gmail.com
Mon Oct 10 09:04:44 CDT 2016


Thanks Ole,

You are perfectly right regarding the error message. For some reason, I misread it. I am sorry about that.

The actual error message, as you point out, makes much more sense!

The rest of your explanation makes sense too, except:

When I declare my closure as @noescape, (the default), I explicitly tell the compiler that, despite the fact closing over it *may* allow it to escape, I, the programmer, guarantee that it will not.

I would understand a warning, but I don’t understand that the compiler insists on putting out an error.

So, while the compiler could perhaps, as you say, perform more sophisticated checks, I don’t even request that. I request however, to be able to tell the compiler that I know better.

If I am wrong, and if I still let the closure escape despite my promise, then I made a programming error, and my code can legitimately crash.

This is no different than using the “!” to promise the compiler that an optional is not nil: if I don’t keep my promise, the program crashes.

Last, in presence of a similar warning (instead of an error), a simple way to squelch the warning would be to make the @noescape declaration explicit.
This would require un-deprecating it.

I now feel that I should propose that as an evolution.

What do you think?

Jean-Denis




> On 10 Oct 2016, at 12:52, Ole Begemann <ole at oleb.net> wrote:
> 
>> 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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20161010/72fec6ab/attachment.html>


More information about the swift-users mailing list