> 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