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

plx plxswift at icloud.com
Thu Feb 4 18:39:19 CST 2016


> On Feb 4, 2016, at 1:47 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>> 
> 
>  s.find(subString, .ignoringCase | .ignoringDiacriticalMarks) -> Range<String.Index>
> 
>> func trimming(characterSet: NSCharacterSet) -> String func
> 
>  s.trimming(.whitespaceAndNewlines)
> 
> Gah; you're right, here.  Keeping a linguistic basis requires backing
> off all the way from “sentence” to “phrase.”  That's actually where I
> started with this guideline, but thought I'd be able to strengthen it.
> Saying “sentence or noun phrase” (if it works) might be better than just
> “phrase” because “noun phrase” is always a term of art, whereas “phrase”
> might just be interpreted casually.

I think sentence-or-noun-phrase covers things “linguistically", but it seems to carve out a pretty territory; other than special-cases (init, operators, label-less functions like `min`), I can’t think of anything that would be:

- reasonably-named (e.g. a name you’d actually want to use)
- *not* satisfying the proposed sentence-or-noun-phrase rule

…is there a good example of such?

Even if that’s right I’m not sure it’s a bad thing, but it’s still broad enough to give me a little pause; it may actually be the easiest way to carve out the non-init, non-operator, non-label-free-functions.

>> …than to win an argument over whether or not “add observer” describes
>> *enough* of the “primary semantics” of this method to fall under the
>> proposed guideline.
> 
> That seems less ambiguous to me than primary focus, and I believe a few
> examples in the guidelines would be enough to settle most debates.

Fair enough. There’s still a subtle ambiguity in "primary semantics” (is it primary in the sense of “describing the most-important part" of the semantics, or is it “primary semantics” in the sense of “describes the majority/most(/etc.) of the semantics”), but examples should be enough to clear it up.

> 
>> 
>> 
>> But that’s just an opinion, and on reflection I don’t think “primary
>> semantic focus” is the clearest formulation, either; I just don’t have
>> anything better.
>> 
>>> 
>>>> This rule seems to cover e.g. `addObserver(_:forKeyPath:)` and
>>>> `addObserver(_:selector:name:object:)` and `encodeObject(_:forKey:)`
>>>> and `present(_:animated:completion:)` (née
>>>> `presentViewController(_:animated:completion:)`), and so on.
>>>> 
>>>> A point to bring up is that under these rules, the “evolution” of a
>>>> name would be different: the just-so story for how
>>>> `addObserver(_:forKeyPath:)` came to be so-called is that it *began*
>>>> as `add(observer:forKeyPath:)`, but b/c the `observer` argument is the
>>>> semantic focus it "made sense to move `observer` into the method
>>>> name”; that is, the assumption is that functions like
>>>> `addObserver(_:forKeyPath:)` are considered to be exceptions to the
>>>> "base convention” and need to be justified.
>>> 
>>> Okay, I understand it, but I'm not sure why it's better.  Please explain
>>> why this is an improvement over the other approach.
>>> 
>>>> Also note that "counter-examples" to rule (a) are anything for which
>>>> no one argument is easily-identifiable as the semantic focus.
>>>> 
>>>> EG, in a function like:
>>>> `adjudicate(plaintiff:defendant:circumstances:)` we can colorably
>>>> claim `circumstances` is a modifier-type parameter, but we don’t—and
>>>> shouldn’t!—treat either `plaintiff` or `defendant` as the
>>>> semantic-focus. If you have two focuses then you have no focus, as it
>>>> were.
>>>> 
>>>> For (b), the intuition is that whenever argument-order is irrelevant,
>>>> arguments should be unlabelled; thus e.g.:
>>>> 
>>>> - min/max: don’t label the arguments
>>>> - hypot: don’t label the arguments
>>>> - copysign: ideally, label the arguments
>>>> - atan2: ideally, label the arguments
>>> 
>>> Those last two may draw some quibbles from the math domain experts, but
>>> I agree with the spirit.
>>> 
>>>> 
>>>> …and so on. Note that these examples are all "free functions”; there
>>>> don’t seem to be many natural examples that *aren’t* free
>>>> functions. 
>>> 
>>> colorMixer.blend(color1, color2)
>>> track.fade(from: initialVolume, to: targetVolume)
>>> 
>>> 
>>>> Also, please don’t be mislead by your familiarity with
>>>> e.g. `copysign` and/or `atan2`; they are used here to illustrate a
>>>> general principle (argument-ordering) only, but in practice such
>>>> highly-familiar “legacy functions” might be best-off given
>>>> special-case handling.
>>> 
>>> Right, so we'd want different examples.
>>> 
>>>> ### III. Naming Functions/Ecosystem Rule
>>>> 
>>>> The previous sections essentially assumed the function names are
>>>> already-chosen (in line with existing conventions) and voice specific
>>>> argument-labeling preferences.
>>>> 
>>>> This section deals with a few changes to how function names should be chosen.
>>>> 
>>>> The over-arching consideration is what I’ve been calling the
>>>> “Ecosystem rule”: whenever a method a member of a “method family"—or
>>>> could foreseeably become a member of such—one should aim for
>>>> consistency in the base name, and use argument-labels as necessary;
>>>> note that method families need not *require* argument labels:
>>>> 
>>>> `contains(_: Point)`
>>>> `contains(_: Line)`
>>>> `contains(_: Shape)`
>>>> 
>>>> …but they *may* require them, as for example in the `login` function
>>>> that has already been discussed.
>>>> 
>>>> The “ecosystem-rule" can also be applied somewhat more-broadly;
>>>> consider the following name suggestions:
>>>> 
>>>> `animate(duration:animations:)`
>>>> `animate(duration:animations:completion:)`
>>>> `animate(duration:delay:options:animations:completion:)`
>>>> `animateUsingKeyFrames(duration:delay:options:animations:completion:)`
>>>> `animateUsingSpring(duration:delay:damping:initialVelocity:options:animations:completion:)`
>>>> 
>>>> …where the first three form an obvious family, and the next two are
>>>> obvious “cousins” of that family due to choice of base names.
>>>> 
>>>> A corollary of this policy is that the rule (3) suggestion—of omitting
>>>> something like `…ForIdentifier...` or `(forIdentifier:…)`—will
>>>> sometimes be overruled out of ecosystem concerns, but I suspect this
>>>> will be somewhat rare in practice.
>>>> 
>>>> For example, consider the following naming suggestions for the “tracks” example:
>>>> 
>>>> // solo method (not part of any family)
>>>> asset.trackWith(trackID)
>>>> 
>>>> // family
>>>> asset.allTracksWith(mediaCharacteristic: …)
>>>> asset.allTracksWith(mediaType: ...
>>>> 
>>>> // the below, instead of `trackWith` or `track(
>>>> asset.firstTrackWith(mediaCharacteristic: ...)
>>>> asset.firstTrackWith(mediaType: …)
>>>> 
>>>> …or the same again, but perhaps dropping the `With` if that’s the overall preference.
>>>> 
>>>> In any case, the overall goal behind the "ecosystem rule” is that
>>>> similar things should be named similarly, and when semantic
>>>> differences are small-enough it makes sense to use argument labels to
>>>> make distinctions; different base names should be for functions that
>>>> are at least a little different from each other.
>>> 
>>> This “rule” seems pretty darned vague, even after all this explanation.
>>> I don't see how it could possibly be stated succinctly,
>>> 
>>> Furthermore, as I wrote to Erica, I have concerns about anything that
>>> gives special treatment to method families, specifically:
>>> 
>>> * I'm wary of adding anything that encourages the creation of
>>> “method families,” which have a higher cognitive overhead than many of
>>> the alternatives.
>>> * A guideline that forces you to change an existing non-overloaded API,
>>> just because you are adding an overload, is problematic.
>> 
>> Understood, and noted, so I won’t press it, other than to point out
>> that method families have come up independently a few times, which may
>> deserve some consideration.
>> 
>> My own sense is they are rather more common in application-level code
>> than would be ideal in standard library code.
> 
> They do occur.  I want them to look/feel good.  I just don't want to
> make special rules for them, if possible.  Let's try to come up with
> guidelines that work for everything with fewer exceptions.
> 
> -- 
> -Dave
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list