Extending trailing closure sugar similar to property accessors

I’d like to hear thoughts on extending trailing closure syntax to avoid long inline closures. A significant benefit to adopting this sugar would be to clarify indentation style for long inline closures. I apologize if this has been brought up before, but I couldn’t find anything searching the list.

There is a lot of discussion about hacking around the issues with inline closures. Here are a few examples:
https://www.natashatherobot.com/swift-trailing-closure-syntax/

https://bugs.swift.org/browse/SR-1199
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160606/020470.html

I think a syntax similar to property accessors to allow multiple trailing closures could make these scenarios feel swifty. Property accessors already have a "get" specialization that is similar to the current trailing closures syntax, so in theory this could be a backwards compatible extension.

func foobar(a: Int, b: Int, completionBlock: ((Int, Int) -> Void), failureBlock: ((Int, Int) -> Void) {
    // ...
}
    
// Current syntax:
foobar(a: 1, b: 2,
    completionBlock: { x, y in
    // ...
    },
    failureBlock: { i, j in
    // ...
    })
    
// A sugar similar to property accessors for multiple trailing closures:
foobar(a: 1, b: 2) {
    completionBlock { x, y in
    // ...
    }
    failureBlock { i, j in
    // ...
    }
}

Best,
Eric

This syntax is ambiguous. Are you passing in two trailing closures to foobar(), or a single trailing closure, inside which you call two top-level functions, completionBlock and failureBlock?

Slava

···

On Nov 2, 2017, at 4:04 PM, Eric Summers via swift-evolution <swift-evolution@swift.org> wrote:

// A sugar similar to property accessors for multiple trailing closures:
foobar(a: 1, b: 2) {
    completionBlock { x, y in
    // ...
    }
    failureBlock { i, j in
    // ...
    }
}

A similar problem exists with property accessors. Although you could call those keywords, they will probably be extensible when behaviors are introduced leading to a similar situation. It can be worked around by making the priority of argument labels higher then function calls within the curly brackets.

Eric

···

On Nov 2, 2017, at 8:51 PM, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 2, 2017, at 4:04 PM, Eric Summers via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

// A sugar similar to property accessors for multiple trailing closures:
foobar(a: 1, b: 2) {
    completionBlock { x, y in
    // ...
    }
    failureBlock { i, j in
    // ...
    }
}

This syntax is ambiguous. Are you passing in two trailing closures to foobar(), or a single trailing closure, inside which you call two top-level functions, completionBlock and failureBlock?

Slava

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

This is not possible in general, since we want the parser to be able to parse code without having knowledge of declarations and their types (which might come from other modules). Overloaded declarations complicate this further.

I agree that the existing property syntax already has this issue, which is unfortunate, but we should not introduce features that make the problem worse.

Slava

···

On Nov 2, 2017, at 5:58 PM, Eric Summers <eric_summers@icloud.com> wrote:

A similar problem exists with property accessors. Although you could call those keywords, they will probably be extensible when behaviors are introduced leading to a similar situation. It can be worked around by making the priority of argument labels higher then function calls within the curly brackets.

That makes sense. I thought there may be a parsing trick involved with the way property accessors are designed.

···

On Nov 2, 2017, at 9:00 PM, Slava Pestov <spestov@apple.com> wrote:

This is not possible in general, since we want the parser to be able to parse code without having knowledge of declarations and their types (which might come from other modules). Overloaded declarations complicate this further.

I agree that the existing property syntax already has this issue, which is unfortunate, but we should not introduce features that make the problem worse.

Slava