[swift-evolution] [Pitch] Brace omission for single-statement n-ary closures

Marc Prud'hommeaux marc at glimpse.io
Tue May 24 14:46:04 CDT 2016

Everyone loves this syntax:

  let pos = [1, -2, 3].map(abs)

This syntax not so much:

  let neg = [1, -2, 3].map({ -abs($0) })

For single-statement closures, ordered parameters could be referenced in an autoclosure-like way using a placeholder for the parameter:

  let neg = [1, -2, 3].map(-abs(_))

The behavior would be the same as the current $0, $1, ... shorthand argument names to inline closures except that parameter re-ordering wouldn't be allowed (the first instance of _ would be $0, the second would be $1, etc). So the following three lines would all be compiled the same:

  let reversed = words.sort( { $0 > $1 } )
  let reversed = words.sort(_ > _)
  let reversed = words.sort(>)

As with autoclosures, noescape rules would be enforced since there wouldn't be any way to specify that self is weak or unowned. So while the following requires use of self to make capture semantics explicit:

  words.lazy.filter({ $0.hashValue == self.hashValue })

These would both raise errors:

  words.lazy.filter(_.hashValue == hashValue)
  words.lazy.filter(_.hashValue == self.hashValue)

Nested closures would also behave the same as with dollar-shorthand:

  let words = ["abc", "def", "hij"]
  let ascii = words.flatMap({ $0.unicodeScalars.filter({ $0.isASCII }) })
  let ascii = words.flatMap(_.unicodeScalars.filter(_.isASCII))

Another example:

  let words: [String?] = ["Hey", "you", nil, "guys"]
  let exclaim = words.flatMap({ $0 }).map({ $0.uppercaseString }).reduce("", combine: { $0+"! "+$1 })
  let exclaim = words.flatMap(_).map(_.uppercaseString).reduce("", combine: _+"! "+_)

Why underscore and not another character like a lone "$" or "."? The meaning of the underscore character as an anonymous ordered placeholder would be consistent with other usages throughout the Swift language. Examples:

  let (_, two, _) = (1, 2.0, "Three") // anonymous tuple property
  words.reduce("", combine: { (x, _) in x }) // anonymous closure parameter
  let advancer = Int.advancedBy(_:limit:) // anonymous function argument
  switch "X" as String? {
  case .Some(_): print("something") // anonymous enum value
  case .None: print("nothing")

And since underscore currently isn't allowed on the right-hand side of an expression, this syntax enhancement shouldn't break any existing code. Lastly, this same syntax for anonymous arguments is used in Scala, so it would already be familiar to a large developer base.

Any yeas or nays?


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160524/6fb17391/attachment.html>

More information about the swift-evolution mailing list