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

Radosław Pietruszewski radexpl at gmail.com
Sat Feb 13 04:51:54 CST 2016


A few random finds/thoughts:

-  func magnifyToFit(rect: Rect)
+  func magnify(toFit rect: Rect)

Intentional? I guess it could be argued either way, but “magnify-to-fit” seems like one phrase.

* * *

Are those guidelines and automatic translations open for further changes and refinement after Swift 3 is released? It will be a *big* change and messing with it further could be painful, but I fear that there’s stuff we might be missing and insights we’ll only have after we start using all this in practice. It would be a shame to freeze it forever if that happens…

* * *

(NSArray)
+  func description(withLocale locale: AnyObject?) -> String
+  func description(withLocale locale: AnyObject?, indent level: Int) -> String

Another case where `with` doesn’t add anything IMHO and in fact makes things slightly confusing. The description isn’t somehow made *with* the locale, it’s just a variant of the `description` property that takes a locale as an setting.

* * *

-  optional func scrollViewShouldScrollTo(top scrollView: UIScrollView) -> Bool
+  optional func scrollViewShouldScroll(toTop scrollView: UIScrollView) -> Bool
   @available(iOS 2.0, *)
-  optional func scrollViewDidScrollTo(top scrollView: UIScrollView)
+  optional func scrollViewDidScroll(toTop scrollView: UIScrollView)

Similar case as “magnify to fit”. the scroll view has nothing to do with “toTop”. It should be:

scrollViewDidScrollToTop(_: UIScrollView)

* * *

I said that in the previous post, but I’ll say it again: looking at the full diff with the refinements applied since the first draft in this thread, I’m really coming around to this proposal. There are still some cases that make me a bit uncomfortable, but it passes the test of “as good as possible, but with fewest results I can’t live with”. So that’s +1 from me ;-)

* * *

PS. If someone wants to see the full diff between the pre-prepositions-inside-parens draft and the latest draft:

curl https://github.com/apple/swift-3-api-guidelines-review/compare/eeca3ac...swift-3.diff | mate

(or your favorite editor of choice. GH doesn’t show the *full* highlighted diff, and unhighlighted diff is hard to read.)

— Radek

> On 13 Feb 2016, at 11:23, Radosław Pietruszewski <radexpl at gmail.com> wrote:
> 
>> On 12 Feb 2016, at 00:19, Douglas Gregor <dgregor at apple.com <mailto:dgregor at apple.com>> wrote:
>> 
>> 
>>> On Feb 11, 2016, at 2:29 PM, Radosław Pietruszewski <radexpl at gmail.com <mailto:radexpl at gmail.com>> wrote:
>>> 
>>>> On 11 Feb 2016, at 20:34, Douglas Gregor <dgregor at apple.com <mailto:dgregor at apple.com>> wrote:
>>>> 
>>>>> 
>>>>> On Feb 11, 2016, at 2:33 AM, Radosław Pietruszewski via swift-evolution <swift-evolution at swift.org <mailto: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.
> 
> I agree, though I thought it was better than nothing.
> 
>> 
>>>>> 
>>>>> 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 <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)
>>  -  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)
> 
> Ah, neat. Probably uncommon overall, but I can see the advantage here, yeah.
> 
>> 
>> 
>>> 
>>> * * *
>>> 
>>> 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 <https://github.com/apple/swift-3-api-guidelines-review/commit/aaec8d0fe9cf82cd6f4088721cf8968a6ac69164>
>> 
>> Essentially, all of those examples above end up with the argument label “for”.
> 
> Ah, nice! That actually helps a lot, and seeing this and other refinements I’m more and more on board with the “prepositions inside parens” idea :)
> 
>> 
>>> 
>>> 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)
> 
> Yep, both seem good to me.
> 
> — Radek

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160213/052063c5/attachment.html>


More information about the swift-evolution mailing list