Hi all,

Here’s a proposal draft to allow one to name any function in Swift. In effect, 
it’s continuing the discussion of retrieving getters and setters as functions 
started by Michael Henson here:

        
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/002168.html

the proposal follows, and is available here as well:

        
https://github.com/DougGregor/swift-evolution/blob/generalized-naming/proposals/0000-generalized-naming.md

Comments appreciated!

Generalized Naming for Any Function

Proposal: SE-NNNN 
<https://github.com/apple/swift-evolution/blob/master/proposals/0000-generalized-naming.md>
Author(s): Doug Gregor <https://github.com/DougGregor>
Status: Awaiting Review
Review manager: TBD
 
<https://github.com/DougGregor/swift-evolution/blob/generalized-naming/proposals/0000-generalized-naming.md#introduction>Introduction

Swift includes support for first-class functions, such that any function (or 
method) can be placed into a value of function type. However, it is not 
possible to specifically name every function that is part of a Swift 
program---one cannot provide the argument labels when naming a function, nor 
are property and subscript getters and setters referenceable. This proposal 
introduces a general syntax that allows one to name anything that is a function 
within Swift in an extensible manner.

Swift-evolution thread: Michael Henson started a thread about the getter/setter 
issue here 
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/002168.html>,
 continued here 
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002203.html>.
 See the Alternatives considered 
<https://github.com/DougGregor/swift-evolution/blob/generalized-naming/proposals/0000-generalized-naming.md#alternatives-considered>
 section for commentary on that discussion.

 
<https://github.com/DougGregor/swift-evolution/blob/generalized-naming/proposals/0000-generalized-naming.md#motivation>Motivation

It's fairly common in Swift for multiple functions or methods to have the same 
"base name", but be distinguished by parameter labels. For example, UIView has 
three methods with the same base name insertSubview:

extension UIView {
  func insertSubview(view: UIView, at index: Int)
  func insertSubview(view: UIView, aboveSubview siblingSubview: UIView)
  func insertSubview(view: UIView, belowSubview siblingSubview: UIView)
}
When calling these methods, the argument labels distinguish the different 
methods, e.g.,

someView.insertSubview(view, at: 3)
someView.insertSubview(view, aboveSubview: otherView)
someView.insertSubview(view, belowSubview: otherView)
However, when referencing the function to create a function value, one cannot 
provide the labels:

let fn = someView.insertSubview // ambiguous: could be any of the three methods
In some cases, it is possible to use type annotations to disambiguate:

let fn: (UIView, Int) = someView.insertSubview    // ok: uses 
insertSubview(_:at:)
let fn: (UIView, UIView) = someView.insertSubview // error: still ambiguous!
To resolve the latter case, one must fall back to creating a closure:

let fn: (UIView, UIView) = { view, otherView in
  button.insertSubview(view, otherView)
}
which is painfully tedious. A similar workaround is required to produce a 
function value for a getter of a property, e.g.,

extension UIButton {
  var currentTitle: String? { ... }
}

var fn: () -> String? = { () in
  return button.currentTitle
}
One additional bit of motivation: Swift should probably get some way to ask for 
the Objective-C selector for a given method (rather than writing a string 
literal). The argument to such an operation would likely be a reference to a 
method, which would benefit from being able to name any method, including 
getters and setters.

 
<https://github.com/DougGregor/swift-evolution/blob/generalized-naming/proposals/0000-generalized-naming.md#proposed-solution>Proposed
 solution

Swift currently has a back-tick escaping syntax that lets one use keywords for 
names, which would otherwise fail to parse. For example,

func `try`() -> Bool { ... }
declares a function named try, even though try is a keyword. I propose to 
extend the back-tick syntax to allow compound Swift names (e.g., 
insertSubview(_:aboveSubview:)) and references to the accessors of properties 
(e.g., the getter for currentTitle). Specifically,

Compound names can be written entirely within the back-ticks, e.g.,

let fn = someView.`insertSubview(_:at:)`
let fn1 = someView.`insertSubview(_:aboveSubview:)`
The same syntax can also refer to initializers, e.g.,

let buttonFactory = UIButton.`init(type:)`
Getters and setters can be written using dotted syntax within the back-ticks:

let specificTitle = button.`currentTitle.get` // has type () -> String?
let otherTitle = UIButton.`currentTitle.get`  // has type (UIButton) -> () -> 
String?
let setTintColor = button.`tintColor.set`     // has type (UIColor!) -> ()
The same syntax works with subscript getters and setters as well, using the 
full name of the subscript:

extension Matrix {
  subscript (row row: Int) -> [Double] {
    get { ... }
    set { ... }
  }
}

let getRow = someMatrix.`subscript(row:).get` // has type (Int) -> () -> 
[Double]
let setRow = someMatrix.`subscript(row:).set` // has type (Int) -> ([Double]) 
-> ()
If we introduce property behaviors into Swift, the back-tick syntax could also 
be used to refer to behaviors, e.g., accessing the lazy behavior of a property:

self.`myProperty.lazy`.clear()
Base names that are meaningful keywords (init and subscript) can be escaped 
with a nested pair of back-ticks:

extension Font {
  func `subscript`() -> Font {
    // return the subscript version of the given font
  }
}

let getSubscript = font.``subscript`()` // has type () -> Font
The "produce the Objective-C selector for the given method" operation will be 
the subject of a separate proposal. However, here is one possibility that 
illustrations how it uses the proposed syntax here:

let getter: Selector = objc_selector(NSDictionary.`subscript(_:).get`) // 
produces objectForKeyedSubscript:
let setter: Selector = objc_selector(NSDictionary.`subscript(_:).set`) // 
produces setObject:forKeyedSubscript:
 
<https://github.com/DougGregor/swift-evolution/blob/generalized-naming/proposals/0000-generalized-naming.md#impact-on-existing-code>Impact
 on existing code

This is a purely additive feature that has no impact on existing code. The 
syntactic space it uses is already present, and it merely extends the use of 
back-ticks from storing a single identifier to more complex names.

 
<https://github.com/DougGregor/swift-evolution/blob/generalized-naming/proposals/0000-generalized-naming.md#alternatives-considered>Alternatives
 considered

Michael Henson proposed 
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/002168.html>
 naming getters and setters using # syntax followed by get or set, e.g.,

let specificTitle = button.currentTitle#get
The use of postfix # is a reasonable alternative here, and more lightweight 
than two back-ticks for the simple getter/setter case. The notion could be 
extended to allow argument labels for functions, discussed here 
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002210.html>.
 The proposals in that discussion actually included type annotations as well, 
but the syntax seems cleaner---and more directly focused on names---without 
them, e.g.,:

let fn = someView.insertSubview#(_:at:)
which works. I didn't go with this syntax because (1) it breaks up Swift method 
names such as insertSubview(_:at:)with an # in the middle, and (2) while 
useful, this feature doesn't seem important enough to justify overloading 
#further.

Joe Groff notes 
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/003008.html>
 that lenses are a better solution than manually retrieving getter/setter 
functions when the intent is to actually operate on the properties. That 
weakens the case this proposal makes for making getters/setters available as 
functions. However, it doesn't address the general naming issue or the desire 
to retrieve the Objective-C selector for a getter/setter.

Can we drop the back-ticks? It's very tempting to want to drop the back-ticks 
entirely, because something like

let fn = someView.insertSubview(_:at:)
can be correctly parsed as a reference to insertSubview(_:at:). However, it 
breaks down at the margins, e.g., with getter/setter references or no-argument 
functions:

extension Optional {
  func get() -> T { return self! }
}

let fn1 = button.currentTitle.get   // getter or Optional<String>.get?
let fn2 = set.removeAllElements()   // call or reference?


        - Doug

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to