[swift-evolution] When to use argument labels, part DEUX

Dave Abrahams dabrahams at apple.com
Tue Feb 9 15:50:21 CST 2016


on Tue Feb 09 2016, Charles Kissinger <swift-evolution at swift.org> wrote:

>> On Feb 9, 2016, at 6:42 AM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> 
>> on Tue Feb 09 2016, Charles Kissinger <swift-evolution at swift.org> wrote:
>> 
>
>>> Comments inline:
>>> 
>>>> On Feb 7, 2016, at 9:54 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> 
>>>> on Sun Feb 07 2016, Charles Kissinger <swift-evolution at swift.org> wrote:
>>>> 
>>>>> Looking over these guidelines again, I think I would be quite happy
>>>>> with them given one very simple change to Rule 2:
>>>>> 
>>>>> If the first argument is part of a prepositional phrase WITH MULTIPLE
>>>>> OBJECTS, put the parenthesis immediately after the preposition.
>>>>> 
>>>>> This eliminates the need for:
>>>>> 
>>>>> a.tracksHaving(mediaType: b)
>>>>> 
>>>>> which I think is inferior to:
>>>>> 
>>>>> a.tracksHavingMediaType(b)
>> 
>> Why do you think it's inferior?
>
> 1) One gripe is that it is much harder to reliably search for
> functions like this in code. You can do it in Xcode with
> Find>References, but if you are on a different platform, using
> different tools or looking at an online repository, you can’t do it
> without resorting to regular expressions. You need to find:
>
> a.tracksHaving(mediaType: b)
> and:
> a.tracksHaving( mediaType: b ) // deliberate or accidental space
> and:
> a.tracksHaving(
>     mediaType: a)
> and:
> a.tracksHaving( // a comment
>     mediaType: a)
>
> The regex search would have to match over line boundaries. Even in
> Xcode, it isn’t novice-friendly because Find>References is relatively
> hidden.

A fair point.

> (This whole problem arises of course only when there could be other
> ‘tracksHaving()’ methods, like tracksHaving(composer:), etc. I expect
> that you would have to generally assume that would be the case for
> methods named this way).
>
> To be fair, you *can* miss occurrences of a.tracksHavingMediaType(b)
> by using a simple text search with ‘.tracksHavingMediaType(‘ -- if
> there is a space before the parenthesis -- but I’m not sure that has
> ever happened to me. Putting a space before the paren in a function
> call is a much less common coding style than space after the paren.

You will also fail to find methods with different later argument labels,
no matter which convention we choose here.  Searchability is a nice
feature, and I agree that it suffers somewhat when long base names are
split up.

> 2) It splits in the middle of a phrase, the least intuitive place to
> do so. It strikes at least some of us as quirky. As you say, this
> (along with the other changes) makes some Cocoa programmers, your main
> constituents, “wildly uncomfortable”, and it has the same effect on
> me, coming from a mostly C++ background (though I have found the Cocoa
> naming conventions to be pleasant to use over the years when writing
> Obj-C).

FWIW, the latest direction
<http://article.gmane.org/gmane.comp.lang.swift.evolution/6342> avoids
that by moving prepositions inside the parentheses.

> 3) This way of treating prepositions and their objects is not
> consistent with the way verbs and their objects are treated:
>
> a.tracksHaving(mediaType: b)
> a.addSubView(b)

Under the latest:

  a.tracks(havingMediaType: b)
  a.addSubView(b)

That's still inconsistent if your expectation is that these two calls have the
same “shape.”  

There's significant consensus that the role of the thing being added is
a fundamental-enough part of the semantics that it should be visible in
the base name.

> Or have I not been keeping up? Is there the intention of using:
> a.add(subView: b)? 

No such intention exists, to date.

> (It would really be a nightmare to search a code base for one
> particular version of an ‘add()’ method, out of what could be dozens
> of different ‘add()’s.
>
> Assuming they are going to be treated differently, it won’t be
> immediately obvious to anyone why this is without reading not just the
> guidelines, but the rationale for the guidelines. How many programmers
> won’t even recall what a prepositional phrase is?

Hopefully, copious examples and links to definitions of grammatical
terms (as I have used throughout the existing guidelines document) will
be enough to guide people in the right direction.

> 4) For me, it reduces readability and “immediate understandability”
> (admittedly subjective). It replaces a nice camelCase word boundary
> and intact phrase with a parenthesis in the middle of the phrase
> followed by a lowerCamelCase word. It doesn’t flow as nicely, possibly
> because there isn’t any common precedent in other programming
> languages for slicing things up this way.

Understood.  I think all of us agree about the oddness of splitting up
the phrase.  How does the latest idea (linked above) look to you?

>
>
> —CK
>> 
>>>> The downside with the latter is that it doesn't scale up.  When you want
>>>> to add a second criterion, you can't just add a defaulted parameter; you
>>>> have to change the signature (breaking code) or add one or more
>>>> overloads (creating cognitive weight for users).
>>> 
>>> Is this really an overriding concern though? I personally would not
>>> choose to optimize for the occasional case of adding a defaulted
>>> parameter at the cost of a general naming/labeling convention that we
>>> both have expressed some discomfort with.
>> 
>> It's not an *overriding* concern; it's one of many.  BTW, I don't
>> consider “some discomfort” on anyone's part to be an overriding concern
>> either.  Most of these changes make Cocoa traditionalists wildly
>> uncomfortable.  While I have compassion for that, the key thing is
>> understandability of Swift code into the future.  
>> 
>>>> It's a (relatively speaking) minor issue, but IMO not glomming all that
>>>> description into the base name also results in code that's easier to
>>>> format in a balanced way, simply because there's a natural place to
>>>> break the line after the parenthesis.
>>> 
>>> I view this in a quite different way. Breaking a line after
>>> 'a.tracksHaving(‘ leaves the reader in quite a bit of suspense! 
>> 
>> Suspense is good in these cases; it means the reader isn't going to stop
>> at the end of the line.  One should feel relief only when one has taken
>> in all the important parts of the call.
>> 
>>> It might be easier to format, but overall readability would suffer.
>> 
>> I don't see how
>> 
>>  a.long.line.ending.with.tracksHavingMediaType(
>>    mp3)
>> 
>> is any more readable than
>> 
>>  a.long.line.ending.with.tracksHaving(
>>    mediaType: mp3)
>> 
>> to me, it's less readable.
>> 
>>>> 
>>>>> On the other hand, functions like:
>>>>> 
>>>>> a.tracksWith(mediaType: b, composer: c)
>>>>> a.moveTo(x: 22, y: 99)
>>>>> 
>>>>> would remain as is, because there are multiple objects for the preposition.
>>>>> 
>>>>> This also neatly solves the ‘moveFrom(a to: b)’ problem. There are two
>>>>> separate prepositional phrases involved, 'from a' and 'to b', each
>>>>> with a single object, so:
>>>>> 
>>>>> move(from: a to: b)
>>>>> 
>>>>> is, I believe, fully compatible with the guidelines.
>>>> 
>>>> I don't see anything in the guidelines I've proposed, even with your
>>>> modification, that would cause "from" to be placed inside the
>>>> parentheses.  The way I read it this case still falls right into B1,
>>>> resulting in "moveFrom(a, to: b)”
>>> 
>>> I must be interpreting B.1 differently than you intended. It appears
>>> to me to be discussing the cases where first arguments *can* be
>>> unlabeled. You seem to be implying here that it says that the first
>>> argument *must* be unlabeled when it forms a part of a grammatical
>>> phrase, otherwise move(from: a, to: b) would be fine. As I read the
>>> guidelines, though, only B.2 (which I would modify) requires
>>> moveFrom(a, to: b), because of the preposition. What am I not getting
>>> here?
>> 
>> 
>> Maybe I was mistaken. I'm working on new wording that allows "from" to
>> move inside the parens under the same guideline that results in argument
>> labels for all arguments when the method is a factory function.  I'll
>> let you know when that's ready.
>> 
>>>>> —CK
>>>>> 
>>>>>> On Feb 5, 2016, at 1:32 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>>>>>> 
>>>>>> 
>>>>>> Given all the awesome feedback I've gotten on this thread, I went back
>>>>>> to the drawing board and came up with something new; I think this one
>>>>>> works.  The previously-stated goals still apply:
>>>>>> 
>>>>>> * describe when and where to use argument labels
>>>>>> * require labels in many of the cases people have asked for them
>>>>>> * are understandable by humans (this means relatively simple)
>>>>>> * preserve important semantics communicated by existing APIs.
>>>>>> 
>>>>>> Please keep in mind that it is a non-goal to capture considerations we
>>>>>> think have a bearing on good names (such as relatedness of parameters):
>>>>>> it's to create simple guidelines that have the right effect in nearly
>>>>>> all cases.
>>>>>> 
>>>>>> A. When arguments can't be usefully distinguished from one another, none
>>>>>> should have argument labels, e.g. min(x,y), zip(x,y,z).  
>>>>>> 
>>>>>> B. Otherwise,
>>>>>> 
>>>>>> 1. At the call site, a first parameter that has no argument label must
>>>>>>   form part of a grammatical phrase that starts with the basename, less
>>>>>>   any trailing nouns.  
>>>>>> 
>>>>>>     print(x)
>>>>>>     a.contains(b)
>>>>>>     a.mergeWith(b)
>>>>>>     a.addGestureRecognizer(x)
>>>>>>          ^~~~~~~~~~~~~~~~~ trailing noun
>>>>>> 
>>>>>>   This phrase must have the correct semantic implications, so, e.g.
>>>>>> 
>>>>>>     a.dismiss(b)           // no, unless a is really dismissing b
>>>>>>     a.dismissAnimated(b)   // no, not grammatical
>>>>>>     a.dismiss(animated: b) // yes, using a label
>>>>>> 
>>>>>> 2. If the first argument is part of a prepositional phrase, put the
>>>>>>   parenthesis immediately after the preposition. 
>>>>>> 
>>>>>>     a.encodeWith(b)
>>>>>>     a.moveFrom(b, to: c)
>>>>>> 
>>>>>>   Thus, if words are required for any reason between the preposition
>>>>>>   and the first argument, they go into the first argument label.
>>>>>> 
>>>>>>     a.tracksWith(mediaType: b, composer: c)
>>>>>>     a.moveTo(x: 22, y: 99)
>>>>>> 
>>>>>> Notes: 
>>>>>> 
>>>>>> a. I would recommend prepositions other than "with" in nearly all
>>>>>> cases, but that's not the point of these rules.
>>>>>> b. I can understand the aesthetic appeal of
>>>>>> 
>>>>>>  a.move(from: b, to: c)
>>>>>> 
>>>>>> but I believe it is not a clear enough improvement to justify
>>>>>> additional complexity in the guidelines.
>>>>>> 
>>>>>> Questions:
>>>>>> 
>>>>>> 1. I'm not expecting these guidelines to make everybody optimally happy,
>>>>>> all the time, but they shouldn't be harmful.  Are there any cases for
>>>>>> which they produce results you couldn't live with?
>>>>>> 
>>>>>> 2. Are there any cases where you'd be confused about how to apply these
>>>>>> guidelines?
>>>>>> 
>>>>>> Thanks in advance for all your valuable input!
>>>>>> 
>>>>>> P.S. Doug is presently working on generating new importer results, based
>>>>>>   on these guidelines, for your perusal.  They should be ready soon.
>>>>>> 
>>>>>> -- 
>>>>>> -Dave
>>>>>> 
>>>>>> _______________________________________________
>>>>>> 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
>>>> 
>>>> -- 
>>>> -Dave
>>>> 
>>>> _______________________________________________
>>>> 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
>> 
>> -- 
>> -Dave
>> 
>> _______________________________________________
>> 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

-- 
-Dave



More information about the swift-evolution mailing list