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

David Owens II david at owensd.io
Thu Feb 4 23:01:10 CST 2016

> On Feb 3, 2016, at 2:42 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
> on Tue Feb 02 2016, David Owens II <swift-evolution at swift.org> wrote:
>> Awesome for putting this together. I think the rules add some needed
>> clarity, but they have the bias that the first argument *should* have
>> a defaulted empty parameter label. 
> I disagree with this as a premise.  IMO they don't have any such bias.
> The guideline says, only under these very specific conditions does one
> omit an argument label.  That would indicate, if anything, a bias
> towards *having* a label.

In one respect, I agree that the guidelines are written with the intention to be more open on the existence of the first argument label. However, when you apply the guidelines, the “very specific conditions” seem to qualify the vast majority of cases. 

Plus, there is this:

> 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.

And all of the following conversations around it. This is why I say there seems to be a bias towards APIs with not having an argument label.

All that being sad said, my post was really about two things:

  1. clarifying the usage of labels in more than just the first parameter's slot while also simplifying the rule landscape, and
  2. debating rule #2, which really seems about naming APIs, not really about argument label usage

I think my critique is still valid, but I'll focus it directly on when the label should be present and leave the debate for rule #2 elsewhere. I think the two are orthogonal issues, and sometimes the “better choice" is really subjective to the APIs being built. However, whether the argument label should exist is actually a much more straight forward issue to address.

The stated goals of the proposal were these:

> * 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.

I think the proposal falls short of the first point: the proposal really only addresses the first argument. There are cases when the other arguments should not be present as well.

If we start with the premise that all parameters should be labeled, then we can have a set of exclusionary rules to help guide the process. I start here because I believe it’s easier to state the cases on when to remove the labels instead of trying to provide rules for both sides.

The rules:

The purpose of an argument label is to provide clear context of the argument’s role within the function. 

No argument labels are necessary when:

  1. The parameters have a unambiguous meaning with the intent of the function
  2. The label would simply be repeating information that is already explicitly or implicitly derived from the function’s name regarding it’s intent

Here are then the examples of good use cases:

No First Argument Labels

a.contains(b)          // yes, satisfies rules 1 and 2
a.contains(object: b)  // no, object is adds no value: it’s implicitly there

a.merging(b)         // yes, satisfies rules 1 and 2
a.merging(items: b)  // no, items adds no value: it’s implicitly there

a.readFrom(u, ofType: b)          // yes, satisfies rules 1 and 2
a.readFrom(source: u, ofType: b)  // no, source is explicitly derived by “From”

a.addObserver(o)            // yes, o has a clear role
a.addObserver(observer: o)  // no, duplicating info 

a.tracksHavingMediaType("Wax Cylinder")             // yes, the first param’s role is clear
a.tracksHavingMediaType(mediaType: "Wax Cylinder")  // no, duplicating info

Keep First Argument Labels Labels

a.dismiss(b)            // no, this seems to be dismissing b
a.dismiss(animated: b)  // yes, intent is to dismiss; b is a modifier on how to animate.

a.read(u, ofType: b)          // no, it’s not clear what u’s role is
a.read(source: u, ofType: b)  // yes, the source being read is not clear, it could be stdin,
                              // or it could be reading from a, etc…

a.tracksHaving("Wax Cylinder")             // no, the param’s role is not clear
a.tracksHaving(mediaType: "Wax Cylinder")  // yes, provides clear context for the param

Ambiguous Argument Labels - Really up to the API surface

a.moveTo(x: 300, y: 400)  // it may not be clear that (x,y) is the movement plane
a.moveTo(300, 400)        // a may provide explicit context for a 2D plane or coordinates

The non-labeled `moveTo` example is also an illustration of why `max` would have no labels:

max(x, y)        // yes, x's and y’s role is unambiguous
max(a: x, b: y)  // no, there is a clear role for each argument

I think this ruleset is clearer and provides guidance for the various choices that are before us with your rule #2. I also think that arguments on how to name an API like “tracksHavingMediaType” are better left elsewhere. These guidelines still help you decide on the argument placement though regardless of which API works best for your purposes.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160204/da1b4380/attachment.html>

More information about the swift-evolution mailing list