> On Dec 26, 2015, at 11:22 PM, Douglas Gregor via swift-evolution
> <[email protected]> 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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution