[swift-evolution] [Pitch] Improving capturing semantics of local functions

John McCall rjmccall at apple.com
Mon Nov 13 03:17:36 CST 2017


> On Nov 12, 2017, at 11:11 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> On Nov 12, 2017, at 12:55 AM, David Hart via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> Hello evolution folks,
>> 
>> After the positive feedback on the idea of improving capturing semantics of local functions, Alex Lynch and I worked on a proposal. Please let us know if you have any feedback:
>> 
>> https://github.com/hartbit/swift-evolution/blob/improving-capturing-semantics-of-local-functions/proposals/XXXX-improve-capture-semantics-of-local-functions.md
> 
> So, quoting the proposal:
> 
>> First of all, this proposal suggests extending the requirement of the self. prefix to local functions, but only if the local function is used as or used inside an escaping closure.
> 
> I don't love that the use of a function many lines away can cause errors in that closure. There's a "spooky action-at-a-distance" quality to this behavior that I don't like.
> 
> The best idea I have is to require local functions to be annotated with `@escaping` if they're to be used in an escaping closure:
> 
>    func foo() {
>        // `local1` is nonescaping since it isn't marked with the @escaping attribute.
>        func local1() {
>            bar()
>        }
>        local1()		// OK, direct call
>        { local1() }()	// OK, closure is nonescaping
>        DispatchQueue.main.async(execute: local1)	// error: passing non-escaping function 'local2' to function expecting an @escaping closure
>        DispatchQueue.main.async { local1() }		// error: closure use of non-escaping function 'local2' may allow it to escape
> 
>        @escaping func local2() {
>            bar()		// error: call to method 'bar' in escaping local function requires explicit 'self.' to make capture semantics explicit
>        }
> 
>        @escaping func local3() {
>           self. bar()	// OK, explicit `self`
>        }
>        DispatchQueue.main.async(execute: local3)	// OK, escaping function
>        DispatchQueue.main.async { local3() }		// OK, escaping closure
>   }
> 
>    func bar() {
>        print("bar")
>    }
> 
> But this would be quite source-breaking. (Maybe it could be introduced as a warning first?)

I like the idea of requiring @escaping to be explicit on local funcs, but I'm worried that it might be too onerous; after all, we infer @escapingness on closures quite successfully.  At the same time, I agree that applying semantic rules based on how the func is used, potentially much later in the function, is really spooky.  I don't have a great alternative right now.

Random note: we currently infer non-escapingness for local funcs that capture ``inout``s, since those cannot be allowed to escape.  In fact, this is the only way to make a local function non-escaping at all.

John.

> 
>> Secondly, this proposal suggests allowing the same capture list syntax from closures in local functions. Capture lists would still be invalid in top-level and member functions.
> 
> 
> I think this is a good idea, but I don't like bringing the already weird use of `in` to actual functions.
> 
> By analogy with the current closure syntax, the capture list ought to go somewhere before the parameter list, in one of these slots:
> 
> 1.	func fn<T>[foo, bar](param: T) throws -> T where T: Equatable { … }
> 2.	func fn[foo, bar]<T>(param: T) throws -> T where T: Equatable { … }
> 3.	func [foo, bar] fn<T>(param: T) throws -> T where T: Equatable { … }
> 4.	[foo, bar] func fn<T>(param: T) throws -> T where T: Equatable { … }
> 
> Of these options, I actually think #4 reads best; 1 and 2 are very cluttered, and 3 just seems weird. But it seems like the one that would be easiest to misparse.
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list