[swift-evolution] When to use argument labels (a new approach)

Dave Abrahams dabrahams at apple.com
Wed Feb 3 19:20:00 CST 2016


on Wed Feb 03 2016, Radosław Pietruszewski <swift-evolution at swift.org> wrote:

> Overall, great guidelines (and +1 to the rules Erica wrote up), and
> I’m +1 on conveying these nuances in the guidelines.
>
>> 2. Words that describe attributes of an *already-existing* instance
>>   should go in the base name rather than in a label:
>> 
>>      a.tracksHavingMediaType("Wax Cylinder")      // yes
>>      a.removeFirstTrackHavingMediaType("BetaMax") // yes
>> 
>>      a.tracks(mediaType: "Wax Cylinder")          // no
>>      a.removeFirstTrack(havingMediaType: "BetaMax") // no
>> 
>>   [yes, we could use "With" instead of "Having", but it's more
>>   ambiguous]
>> 
>>   Words that describe attributes of an instance *to be created* should
>>   go in argument labels, rather than the base name (for parity with
>>   initializers):
>> 
>>      AudioTrack(mediaType: "BetaMax")                   // initializer
>>      trackFactory.newTrack(mediaType: "Wax Cylinder")   // yes
>> 
>>      trackFactory.newTrackWithMediaType("Wax Cylinder") // no
>
> The rationale for doing this is stronger when we talk about automatic
> translation of Objective-C APIs.

For better or worse, it is a requirement that Cocoa as imported very
closely approximates full conformance to the guidelines we choose.  We
are shooting for consistency across APIs used in swift.

> But in APIs designed for Swift, I feel like this is wrong IMHO, because:
>
> - “media type” is still a parameter, so it shouldn’t be in the base
>   name itself

That doesn't seem obvious to me.  Whether that "should" be in the base
name depends on what guidelines we choose.  

> - this breaks the symmetry with other methods due to the reason above
>   (like the “newTrack” you mentioned yourself) 

Yes, it would be more consistent if these two cases were the same.  

> - doesn’t play well with method families (searching for tracks is
>   searching for tracks. the criteria for search are just parameters).

I don't really believe that “method families” are something we want to
optimize for in Swift.  There are almost always alternatives that impose
lower cognitive overhead on users.

> If we do
>
>    trackFactory.newTrack(mediaType: "Wax Cylinder")   // yes
>
> I don’t see why it’s OK to do
>
>    a.tracksHavingMediaType("Wax Cylinder")      // yes

That's just the consistency argument again, right?

> Of course just “tracks” is confusing, and we agree on that, but I
> would strongly recommend that for new APIs we don’t just name the
> method with a word of an already-existing instance, rather, we start
> it with a verb:
>
> a.findTracks(mediaType: “BetaMax”) // or “searchTracks”, or alternatively “tracksMatching"
> a.removeFirstTrackMatching(mediaType: “BetaMax”)   — ad 2
> fac.newTrack(mediaType: “Wax Cylinder”)
>
> Symmetric, predictable, follows the same convention, plays well with
> method families (i.e. different search criterion than media type), and
> no clarity problems.

Unfortunately, this is the reality:

1. The pattern of omitting prefix verbs like “get” and “find” is
   something of a sacred cow; I think it would be very hard to sell to
   certain important people.

2. if we were to standardize on the opposite, we would need an
   objective-C import strategy that would add these verbs automatically.

If you can get a handle on solving #2, it *might* be worth me taking a
shot at solving #1. Otherwise, I'm afraid this idea is dead in the
water.  Nothing that leaves glaring inconsistencies between imported
Cocoa and the API guidelines is going to be acceptable.

> Ad 2: I can see why you don’t like “removeFirstTrack”. It sounds like
> removing _the_ first track, rather than the first track that matches
> criteria in parameters list. Perhaps a word like “Matching” would work
> well to fix this concern. (And sounds/conveys intention better than
> “with” or “having” IMHO)

There are contexts in which "matching" is more ambiguous than "having",
e.g.

    x.trackMatchingMediaType(t) // track the matching media type?

    x.trackHavingMediaType(t)   // track is obviously a non-verb here.

Yes, I see how this relates to your "put back the verb" idea.

>
> Just my 2¢,
> — Radek
>
>> On 03 Feb 2016, at 01:32, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> 
>> This thread is related to the review of new API guidelines, but it's not
>> a review thread; it's exploratory.  The goal is to come up with
>> guidelines that:
>> 
>> * describe when and where to use argument labels
>> * require labels in many of the cases people have asked for them
>> * are understandable by humans
>> * preserve important semantics communicated by existing APIs.
>> 
>> Here's what I'm thinking
>> 
>> 1. If and only if the first argument could complete a sentence*
>>   beginning in the base name and describing the primary semantics of
>>   the call, it gets no argument label:
>> 
>>     a.contains(b)  // b completes the phrase "a contains b"
>>     a.mergeWith(b) // b completes the phrase "merge with b"
>> 
>>     a.dismiss(animated: b) // "a, dismiss b" is a sentence but 
>>                            // doesn't describe the semantics at all, 
>>                            // thus we add a label for b.
>> 
>>     a.moveTo(x: 300, y: 400) // "a, move to 300" is a sentence 
>>                              // but doesn't describe the primary 
>>                              // semantics, which are to move in both
>>                              // x and y.  Thus, x gets a label.
>> 
>>     a.readFrom(u, ofType: b) // "a, read from u" describes
>>                              // the primary semantics, so u gets no
>>                              // label. b is an
>>                              // option that tunes the primary
>>                              // semantics
>> 
>>   [Note that this covers all the direct object cases and, I believe,
>>   all the default argument cases too, so maybe that exception can be
>>   dropped.  We still need the exceptions for full-width type
>>   conversions and indistinguishable peers]
>> 
>>   Note: when there is a noun in the base name describing the role of the
>>   first argument, we skip it in considering this criterion:
>> 
>>      a.addObserver(b) // "a, add b" completes a sentence describing 
>>                       // the semantics.  "Observer" is omitted in 
>>                       // making this determination.
>> 
>> * We could say "clause" here but I think making it an *independent*
>>  clause doesn't rule out any important use-cases (see
>>  https://web.cn.edu/kwheeler/gram_clauses_n_phrases.html) and at that
>>  point, you might as well say "sentence," which is a more
>>  universally-understood term.
>> 
>> 2. Words that describe attributes of an *already-existing* instance
>>   should go in the base name rather than in a label:
>> 
>>      a.tracksHavingMediaType("Wax Cylinder")      // yes
>>      a.removeFirstTrackHavingMediaType("BetaMax") // yes
>> 
>>      a.tracks(mediaType: "Wax Cylinder")          // no
>>      a.removeFirstTrack(havingMediaType: "BetaMax") // no
>> 
>>   [yes, we could use "With" instead of "Having", but it's more
>>   ambiguous]
>> 
>>   Words that describe attributes of an instance *to be created* should
>>   go in argument labels, rather than the base name (for parity with
>>   initializers):
>> 
>>      AudioTrack(mediaType: "BetaMax")                   // initializer
>>      trackFactory.newTrack(mediaType: "Wax Cylinder")   // yes
>> 
>>      trackFactory.newTrackWithMediaType("Wax Cylinder") // no
>> 
>> 3. (this one is separable) When the first argument is the *name* or
>>   *identifier* of the subject in the base name, do not label it or
>>   describe it in the base name.
>> 
>>      a.transitionToScene(.GreatHall)               // yes
>>      a.transitionToSceneWithIdentifier(.GreatHall) // no
>> 
>>      let p = someFont.glyph("propellor")           // yes
>>      let p = someFont.glyphWithName("propellor")   // no
>>      let p = someFont.glyph(name: "propellor")     // no
>> 
>> Thoughts?
>> 
>> -- 
>> -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