[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