> On Nov 12, 2017, at 12:55 AM, David Hart via swift-evolution 
> <swift-evolution@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?)

> 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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to