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

Dave Abrahams dabrahams at apple.com
Tue Feb 2 18:32:54 CST 2016


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



More information about the swift-evolution mailing list