[swift-evolution] Closure Syntax

Ethan Diamond edgewood7558 at gmail.com
Wed Dec 30 13:43:24 CST 2015


Reasonable. That all makes sense.

For clarity's sake, there's really two syntactic issues that I think would
be good to address. The first, which I think is the far bigger problem,
which is that right now a list of params with closures is very hard to
read. For example, this requires mental effort to decode whether this is
returning an Int, or a closure returning an Int:

func makeIncrementer(forIncrement amount: Int) -> () -> Int {

}

And the second being that stylistically, having the params on the
inside of the closure is breaking precedent of params outside of the
block of code without gaining much.

Perhaps we could adopt the Obj-C ^ as a closure indicator. I think
with existing Swift syntax, a lot of the confusion that caused
www.fuckingblocksyntax.com would be avoided.

=== Local variable / property ===:

var closure = ^(Int) -> Bool

or

var closure = ^(number: Int) -> Bool {

    if (number == 3) { return true }

}

=== Method param ===

func makeIncrementer(forIncrement amount: Int) -> ^() -> Int {

or

func makeIncrementer(forIncrement amount: Int) -> ^(() -> Int) {

=== Argument ===

func makeIncrementer(forIncrement amount: ^((Int) -> Bool)) -> Bool {}

makeIncrementer(forIncrement: ^(number: Int) {

   if (number == 3) { return true }

})

=== typealias ===

typealias CustomType = ^(String) -> Bool

=== Takes no params, returns void (We take for granted if there's no
return, it's void) ===

^()


And I think we can use all the shorthands we currently use:


=== Calling no params, takes void ===

functionWithVoidCallback {

   //Do a thing

}


=== Using $0 $1 syntax ===

func compare(_ comparator: ^(a: Int, b: Int) -> Bool) { }

compare {

  %0 > %1

}

By having ^ mark an upcoming closure, I think it's a lot easier to
follow what's going on with declarations because as you read left to
right, you're prepped that a closure syntax is coming up as you read
left to right. It also allows you to keep the params outside of the
closure, which I think is a win. Closure params would also have the
same syntax everywhere, and be extremely similar to normal method
calls which would be easier for new Swift users.

-E


On Tue, Dec 29, 2015 at 10:13 PM, David Waite <david at alkaline-solutions.com>
wrote:

>
> On Dec 29, 2015, at 5:18 PM, Ethan Diamond via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> I guess the core of the question for me is why have the concept of a
> closure at all when they're harder to read while acting the same way that
> functions do? I'm not a huge fan of Javascript, but the consistancy between
> function declarations and anonymous functions is something I feel they got
> right. JS syntax for everything that receives parameters and possibly
> returns a value is entirely consistent.
>
>
> Some of this is because Javascript doesn't have to declare types or return
> values and it is even loose with arguments and is somewhat confusing (and
> dynamic) with “this”. For Swift, which requires knowledge about the
> arguments and return values needed by callers, it makes sense to have two
> different syntaxes depending on whether or not this knowledge is being
> defined by contract or being inferred by context.
>
> And with ES2015 there are now multiple styles, partially to resolve the
> issues with capturing “this” and partially because writing “function”
> everywhere is visually distracting.
>
> Let's take the anonymous function style:
>
> func asyncWithCallback(_ : func (String) -> Bool)
>
> asyncWithCallback(func (param) {
>     return param == "string"
> })
>
> Particularly for someone new to the language is both clearer and shorter
> than this, which makes the caller rewrite the return type in the closure:
>
> func asyncWithCallback(_ : String -> Bool)
>
> asyncWithCallback {
>   (param: String) -> Bool in
>   return param == "string"
> }
>
>
> Or I could use:
>
> asyncWithCallback {
>     param in
>     return param == "string"
> }
>
>
> or even:
>
> asyncWithCallback { $0 == "string” }
>
>
> A function defines a name and a contract for use and definition, while
> closures are only semantically valid once defined by a context. I can
> understand the stylistic desire to have closures declare arguments outside
> a block and to be closer to function syntax. However, using “func"
> anonymously to indicate a different syntax with a different set of options,
> potentially inferred input types, and an inferred existence of output as
> well as output type might be equally confusing. Perhaps another keyword
> could be used for this purpose.
>
> However this new keyword would need to work with, and avoid adding visual
> distraction to, the “$0 == “string” case above.
>
>
> It still fits your unwritten rule to be able to compose language features
> in Swift, assuming you leave the same syntactic sugar:
>
> func if (_ control: Bool, _ path: func ()) {
>
>   if (control) {
>
>      path()
>
>   }
>
> }
>
> if (a == b) {
>
>   //LETS DO SOME STUFF
>
> }
>
> You probably realize this but closures and blocks have different control
> flow, so for instance the above would absorb/malfunction on returns as well
> as attempts to break/continue outer loops.
>
> -DW
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151230/3351381d/attachment.html>


More information about the swift-evolution mailing list