[swift-evolution] Closure Syntax

Ethan Diamond edgewood7558 at gmail.com
Sun Dec 27 16:30:12 CST 2015


I realize this is on the commonly rejected list, but I really find closure
syntax to be one of the more unintuitive and unreadable parts of Swift so
I'd like to try to influence it. "Clarity at the point of use" is one of
the main stated goals of Swift, and the fact that
http://goshdarnclosuresyntax.com/ exists shows me that it's not just me
that thinks the syntax could be improved. I believe that we can get very
close to the same results in line length and expressiveness while making
the language much more readable and clear.

Let's start with a few use cases to illustrate what I mean when I say that
reading closure syntax is difficult. Most programmers scan left to right,
so when I see this property declaration:

var thing: Int

My brain reads that as a property of a class that's an integer. Unless of
course there's this:

var thing: Int -> Int

Boom, context switch. If you've read "Int" than any following syntax should
be a modifier on Int. For example, Int? works great, because in my head
it's still an Integer, just an optional form of that Integer. While it's
not a huge change in that example, lets take a more complicated one:

var thing: (String -> (), Int, (Int, Int) -> Bool)) -> Bool

Reading that left to right requires all sorts of context switching in my
brain. I can't even tell at first glance how many params are in that
closure. Reading left to right, you read "First parameter, string, no wait,
closure that takes string, and returns void. Second param, Int. Third
param, tuple with two ints, no wait, closure that takes two ints and
returns bool." I just doesn't have much clarity.

I believe it's already been proposed, but I don't feel there's a strong
enough difference between a closure and a function to justify a different
syntax. Let's replace my examples above with anonymous function syntax.

var thing: func (Int) -> Int

Reading left to right, it reads the way that I think about it "A function
that takes an integer and returns an integer."

var thing: func(func (String), Int, func (Int, Int) -> Bool) -> Bool

Again, reading left to right this is a win. "Thing is an anonymous
function. First param, a function that takes a string. Second param, Int.
Third param, a function that takes two ints and returns bool." It reads
like people think.

Another strength is it lets us both use the same syntax for closures as we
would expect, while letting us use just about all of the same shorthands we
gain with closures. We could call normally like this, with the return type
implied when async is called:

func async(callback: func (Bool) -> Bool))

async(func (successful: Bool) {
   return !successful
});

We could still permit this:

func async(callback: func ())

async {
  //Do callback stuff here
}

We could still permit this:

func sort(sortfunc: func(Int, Int) -> Bool)

sort {
  $0 > $1
}

We could add this:

let greaterThan: func (number: Int) -> Bool = {
   number > 5
}

There would also be a few small wins, such as no longer needing "()" to
represent a void return, since any function without a return type would
imply a void return.

I understand that a big part of the decision for current closure syntax is
to help the compiler, but I believe by doing so you're going against the
main principles you laid out in your api design guidelines (
https://swift.org/documentation/api-design-guidelines.html). Current
closure syntax is not clear and breaks precedent of all other function like
declarations having the parameters listed outside of the curly braces.

Thanks for listening, and great job on Swift so far.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151227/5f323bb6/attachment.html>


More information about the swift-evolution mailing list