> On Dec 26, 2015, at 11:22 PM, Douglas Gregor via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 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
>  
> <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
>  
> <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:)`
This part seems reasonable to me.
> 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]) 
> -> ()
At least as far as pure Swift is concerned, for unapplied access, like 
`UIButton.currentTitle`, I think it would be more consistent with the way 
method references works for that to give you the getter (or lens) without 
decoration. instance.instanceMethod has type Args -> Ret, and 
Type.instanceMethod has type Self -> Args -> Ret; by analogy, since 
instance.instanceProperty has type Ret or inout Ret, it's reasonable to expect 
Type.instanceProperty to have type Self -> [inout] Ret. Forming a getter or 
setter partially applied to an instance feels unmotivated to me—{ 
button.currentTitle } or { button.currentTitle = $0 } already work, and are 
arguably clearer than this syntax.

I acknowledge that this leaves forming selectors from setters out to dry, but I 
feel like that's something that could be incorporated into a "lens" design 
along with typed selectors. As a rough sketch, we could say that the 
representation of @convention(selector) T -> inout U is a pair of getter/setter 
selectors, and provide API on Selector to grab the individual selectors from 
that, maybe Selector(getterFor: UIView.currentTitle)/(setterFor: 
UIView.currentTitle). I don't think get/set is a good interface for working 
with Swift properties, so I don't like the idea of building in language support 
to codify it beyond what's needed for ObjC interaction.
> 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?
>From what I remember, the bigger concern with allowing foo(bar:bas:) without 
>backticks is parser error recovery. The unambiguity with call syntax depends 
>on having the `:)` token pair at the end. The edit distance between 
>foo(bar:bas:) and a call foo(bar: bas) or work-in-progress call foo(bar: x, 
>bas: ) is pretty slight, and would be tricky to give good diagnostics for. If 
>we felt confident we could give good diagnostics, I'd support removing the 
>backticks.

-Joe

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

Reply via email to