[swift-evolution] [Proposal draft] Generalized Naming for Any Function

T.J. Usiyan griotspeak at gmail.com
Mon Dec 28 09:05:46 CST 2015


Do things get any better if we combine the proposed changes and remove the
bare case? Begin function reference with some symbol (# here but it doesn't
matter), only use back tics to disambiguate keywords (which lines up with
their current use) and remove the unadorned case to avoid ambiguity.

```swift
class Foo {
func doSomething() { }
func doSomething(value: Int) { }
func sub
}

let fn = Foo#doSomething // no longer allowed
let fn = Foo#doSomething() // okay
let fn2 = Foo#doSomething(_:) // okay

// and

let getRow = someMatrix#`subscript`(row:).get

```



On Sun, Dec 27, 2015 at 10:40 PM, Douglas Gregor via swift-evolution <
swift-evolution at swift.org> wrote:

>
> On Dec 27, 2015, at 12:27 AM, Frederick Kellison-Linn via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Given that someView.insertSubview(_:at:) can be correctly parsed, I would
> strongly lean towards the no-backtick alternative mentioned at the end. I
> feel as though the backticks end up looking very cluttered (particularly
> when you get into the double-nested backticks), and it seems cleaner to be
> able to reference a method as it was declared rather than having to add
> extra syntax.
>
> In reference to the issues noted with this approach:
>
> IMO, there is already enough syntactic difference between getters/setters
> and normal methods to justify requiring a different syntax to reference
> them. For instance, the # syntax could be used so that,
> button.currentTitle.get would reference Optional<String>.get, and
> button.currentTitle#get would reference the getter. Or,
> button.`currentTitle.get` could reference the getter (i.e. backticks are
> only required in cases that are ambiguous).
>
> I also think it is reasonable to require that in the case of a method with
> no arguments such as set.removeAllElements, the programmer be expected to
> know the difference between the expression with and without the trailing
> parenthesis. After all, that distinction already exists in the language,
> and would not disappear with this proposed addition. If a parallel syntax
> for referencing methods with no arguments is strongly desired, perhaps
> something such as set.removeAllElements(:), set#removeAllElements(), or
> similar could be used, though I think that the present system for
> referencing these methods is sufficient.
>
> Are there other obvious reasons why this alternative wouldn’t work? I
> think it is the cleanest of the alternatives and avoids littering the code
> with backticks.
>
>
> Not having the back-ticks means that you will need to use contextual type
> information to disambiguate the zero-parameter case from other cases. For
> example:
>
> class Foo {
> func doSomething() { }
> func doSomething(value: Int) { }
> }
>
> let fn = Foo.doSomething // ambiguous
> let fn2 = Foo.doSomething(_:) // okay
> let fn3: (Foo) -> () -> Void = Foo.doSomething // okay
> let fn3: (Foo) -> (Int) -> Void = Foo.doSomething // okay
>
> My general complaint with the “drop the backticks” approach is that it
> doesn’t solve the whole problem. Sure, it solves 95% of the problem with a
> little less syntax, but now you need to invent yet another mechanism to
> handle the other cases (#set, contextual type disambiguation, etc)… which
> seems inconsistent to me.
>
> - Doug
>
>
> On Dec 26, 2015, at 11:22 PM, Douglas Gregor via swift-evolution <
> swift-evolution at 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
>
> 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
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>  _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151228/9ec2e94d/attachment.html>


More information about the swift-evolution mailing list