[swift-evolution] [Guidelines, First Argument Labels]: Prepositions inside the parens

Matthew Judge matthew.judge at gmail.com
Thu Feb 11 19:50:46 CST 2016



> On Feb 11, 2016, at 18:19, Douglas Gregor via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 
>>> On Feb 11, 2016, at 2:29 PM, Radosław Pietruszewski <radexpl at gmail.com> wrote:
>>> 
>>>> On 11 Feb 2016, at 20:34, Douglas Gregor <dgregor at apple.com> wrote:
>>>> 
>>>> 
>>>>> On Feb 11, 2016, at 2:33 AM, Radosław Pietruszewski via swift-evolution <swift-evolution at swift.org> wrote:
>>>>> 
>>>>> Hi everybody,
>>>>> 
>>>>> Having looked at some examples, the API guidelines working group members
>>>>> that were present this morning agreed we really want prepositions inside
>>>>> the parentheses of method calls.
>>>> 
>>>> I find that… surprising.
>>>> 
>>>> Between these two (sorry to repeat the same example again):
>>>> 
>>>> func trackWith(trackID trackID: CMPersistentTrackID) -> AVAssetTrack?
>>>> func track(withTrackID trackID: CMPersistentTrackID) -> AVAssetTrack?
>>>> 
>>>> #1 seems nicer and clearer to me. Having “with” as the first word glued to a parameter label looks bizarre to my eyes:
>>>> 
>>>> As far as I understand it, the whole reason to keep “with” etc in many APIs was to make cases like this one clearer. Because “track” as a name doesn’t tell you much. Someone said that having the method name end with “With” creates a sense of suspense, and to me that was precisely what was a good thing about it. It’s not just “track”, it’s a “track with” — ooh, here come the criteria for the track! Having removed “with” from the name itself, we lose, IMHO, the clarity this word was supposed to bring in initializer/getter/finder-like methods. And we still keep the word later inside the parens, but to my eyes it no longer helps clarity, just exists as a vacuous, needless word.
> 
> *Personally*, I don’t find the “with” to be compelling in either case. Presumably, it is implying that this is a “find” rather than a “create” operation, but I don’t consider “with” a good way to communicate that… the optional result type and lack of a verb like “add” or “insert” implies “find” stronger than “with”, IMO.
> 
>>>> 
>>>> Another reason I don’t like this, say we have:
>>>> 
>>>> 	a.tracks(withMediaType: b, composer: c)
>>>> 
>>>> This no longer looks symmetrical across the parameters. First parameter has label “with”, second doesn’t. The previous version:
>>>> 
>>>> 	a.tracksWith(mediaType: b, composer: c)
>>>> 
>>>> Didn’t have that problem.
>>>> 
>>>> I fear that people will take that as a signal that they should make the whole method, including parameter labels, sound like an English sentence and will start applying needless words like “and”:
>>>> 
>>>> 	a.tracks(withMediaType: b, andComposer: c)
>>>> 
>>>> To avoid this weird-looking construct where the first parameter has a starting preposition, and other parameters don’t. Again:
>>>> 
>>>> 	a.tracksWith(mediaType: b, composer: c)
>>>> 
>>>> Doesn’t have this problem, because while the method name part ends with “With”, the parameters are consistently just nouns.
>>>> 
>>>> So -1 from me on this. Moving prepositions inside parens look like a step back from the Part DEUX Proposal.
> 
> When we were looking through the results, it seemed like cases where the preposition distributed to multiple arguments were fairly rare… rare enough that it didn’t seem worth complicating the rules or giving up the gains we got elsewhere from moving the prepositions inside.
> 
>>>> 
>>>> Would you mind elaborating on the working group's rationale for moving prepositions inside parens?
>>> 
>>> A couple of reasons that I, personally, found motivating (some of which came up on this list before):
>>> 
>>>   (1) A prepositional phrase is a grammatical entity, and we probably shouldn’t split a grammatical phrase across ‘(‘.
>>>   (2) It seemed to separate “what the method does” (base name) from “how it does it” (argument label) more effectively.
>>>   (3) Related to (2), it pulled out more method families, where we had the same basic operation (described by the base name) and the argument labels differentiated how we got to that result.
>>> 
>>> … and we spent a while looking at the diff of Cocoa, here:
>>> 
>>> 	https://github.com/apple/swift-3-api-guidelines-review/commit/b22b62bb98e5d44b2528b237d18efe96bf2940d6
>>> 
>>> 	- Doug
>> 
>> Thank you.
>> 
>> I’d love to see a response from the team as for my concerns in the post above — I wonder if the arguments were not compelling because I’ve missed something, or simply that the rationale _for_ prepositions inside the parens seemed stronger.
>> 
>>>   (1) A prepositional phrase is a grammatical entity, and we probably shouldn’t split a grammatical phrase across ‘(‘.
>> 
>> A fair point — I guess I just don’t find it as important. Either way, it’s not an English sentence, only English-like.
>> 
>>>   (3) Related to (2), it pulled out more method families, where we had the same basic operation (described by the base name) and the argument labels differentiated how we got to that result.
>> 
>> 
>> Any examples? How was that different from having a preposition just before the paren?
> 
> Here’s a fun set of examples from NSGradient:
> 
>  -  func drawFrom(startingPoint: Point, to endingPoint: Point, options: NSGradientDrawingOptions)
>  -  func drawIn(rect: Rect, angle: CGFloat)
>  -  func drawIn(path: NSBezierPath, angle: CGFloat)
>  +  func draw(from startingPoint: Point, to endingPoint: Point, options: NSGradientDrawingOptions)
>  +  func draw(in rect: Rect, angle: CGFloat)
>  +  func draw(in path: NSBezierPath, angle: CGFloat)
>     func drawFromCenter(startCenter: Point, radius startRadius: CGFloat, toCenter endCenter: Point, radius endRadius: CGFloat, options: NSGradientDrawingOptions)

Why isn't this:
func draw(fromCenter startCenter: Point, radius startRadius: CGFloat, toCenter endCenter: Point, radius endRadius: CGFloat, options: NSGradientDrawingOptions)


>  -  func drawIn(rect: Rect, relativeCenterPosition: Point)
>  -  func drawIn(path: NSBezierPath, relativeCenterPosition: Point)
>  +  func draw(in rect: Rect, relativeCenterPosition: Point)
>  +  func draw(in path: NSBezierPath, relativeCenterPosition: Point)
> 
> 
>> 
>> * * *
>> 
>> I’ve given the diff a look again, and I can now see how some methods look really nice after the change, and only some make me slightly uncomfortable.
>> 
>> func value(at index: Int) -> AnyObject!
>> func read(from url: URL, options: ….)
>> class func strokeLine(from point1: Point, to point2: Point)
>> func appendWithOval(in rect: Rect)
>> func sendAction(on mask: Int) -> Int
>> func rows(in rect: Rect) -> NSRange
>> func translateOrigin(to translation: Point)
>> 
>> I actually like those a lot! There’s no need to repeat parameter name/type information in argument label, because it’s going to be obvious in context on call site. But having a preposition, just alone by itself, actually is a nice thing in explaining the first argument and the method semantics.
>> 
>> What I’m not so sure about is when the preposition is glued to a noun. And I guess it’s largely because the noun seems to repeat type information that’s not needed for clarity at call site:
>> 
>> 	func accessibilityFrame(forRange range: NSRange) -> Rect
>> 	func fractionOfDistanceThroughGlyph(forPoint aPoint: Point) -> CGFloat
>> 	func borderColor(forEdge edge: RectEdge) -> NSColor?
>> 	func value(forDimension dimension: NSTextBlockDimension) -> CGFloat
>> 	func cellFrame(forTextContainer textContainer: NSTextContainer, proposedLineFragment lineFrag: Rect, glyphPosition position: Point, characterIndex charIndex: Int) -> Rect
>> 
>> Why are here the nouns not trimmed like in the examples above?
> 
> I had a ban on creating “vacuous” argument labels from long ago. It didn’t kick in much before, but I removed it in the follow-up commit to what you’re looking at:
> 
> 	https://github.com/apple/swift-3-api-guidelines-review/commit/aaec8d0fe9cf82cd6f4088721cf8968a6ac69164
> 
> Essentially, all of those examples above end up with the argument label “for”.
> 
>> 
>> I think:
>> 
>> 	accessibilityFrame(for: someRange)
>> 	fractionOfDistanceThroughGlyph(for: somePoint)
>> 	borderColor(for: edge)
>> 	value(for: someTextBlockDimension)
>> 	cellFrame(for: someTextContainer, …)
>> 
>> Would also work. No?
> 
> Yep, the next commit ;)
> 
>> 
>> In other cases, I’m bothered by the preposition glued to an argument label, because the preposition seems unnecessary:
>> 
>> 	func copy(withZone zone: Zone = nil) -> AnyObject
> 
> Here, I feel like we need *a* label because we aren’t copying the first argument… we’re copying “self” and using the first argument. The second commit I referenced above would make this just “with”; I, personally, would prefer “coder” or something meaningful like “into”.
> 
>> 	optional func shouldPerformSegue(withIdentifier identifier: String, sender: AnyObject?) -> Bool
>> 	func statusItem(withLength length: CGFloat) -> NSStatusItem
>> 	func instantiateController(withIdentifier identifier: String) -> AnyObject
> 
> The “with”s don’t seem to add anything here.
> 
>> 	func performClickOnCell(atColumn column: Int, row: Int)
>> 
>> I guess this is mostly a problem with “with”s. The last example is more arguable — what bothers me there more is the inconsistent treatment of argument labels (first label starts with a preposition that conveys semantics for both parameters, and the second label is just a parameter name).
> 
> Here, the “at” distributes, but it’s also not needed for clarity. We’d be find with either
> 
> 	func performClickOnCellAt(column: Int, row: Int)
> 
> or 
> 
> 	func performClickOnCell(column: Int, row: Int)
> 
> 
> 	- Doug
> 
> _______________________________________________
> 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/20160211/d891a91e/attachment.html>


More information about the swift-evolution mailing list