[Review] SE-0023 API Design Guidelines

I really like the general spirit of these guidelines. I particularly
appreciate their emphasis on clarity at the point of use, and their
recognition that both brevity and verbosity can be the enemy of
clarity.

Some of the particulars of the guidelines haven’t worked well for me
in practice — and I see from this thread that others have hit some of
the same problems. The guidelines as they stand feel like they’ve
mostly been vetted against a bunch of ADTs (which is probably true —
stdlib?), and could use exposure to a broader range of libraries.

They've been vetted against all of Cocoa (to the best of our
ability—it's huge) and against a couple of sample projects, Lister and
DemoBots. This was a major effort and we endeavored to cover all the
bases. However, we recognize that there's a lot more code out there
than we can possibly look at, so we're very happy to get more input from
the community.

Immediately after the guidelines were published, before this review
began, I tried applying them to Siesta. The project has 244 public
declarations, of which I found 28 that the guidelines seemed to
recommend changing. Of those 28, after much reflection and discussion,
I ended up changing only 7 to match the guidelines (and also cleaning
up several others, but in a non-guideline-compliant way).

In short, in a real-world project, pre-guidelines code agreed with the
guidelines 89% of the time, but where it disagreed, the guidelines
achieved only a 25% acceptance rate with the curmudgeonly developers.

You can follow that discussion here:

  Siesta API guidelines audit.md · GitHub
<https://gist.github.com/pcantrell/22a6564ca7d22789315b&gt;
  Update API for Apple’s newly released API design guidelines · Issue #15 · bustoutsolutions/siesta · GitHub
<Issues · bustoutsolutions/siesta · GitHub;

Several places where we rejected the guidelines relate to the raging
debate about first argument labels. Here’s a rundown of those
particular cases. (Since this message will be a long one, I’ll share
in a separate message some notes on the other places where we rejected
the guidelines on questions other than the first arg label.)

Hopefully some more concrete examples can be useful in informing the
discussion.

_____________________________

Quick context: there are things called resources. Resources can have
observers. Observers are either self-owned or have an external owner
object. Observers can either conform to a protocol or be closures; if
the the latter, then they _must_ have an external owner (because
closures aren’t objects).

There are thus three different methods to add observers to a resource
— though they all cover the same underlying notion of “observer” (and
in fact all boil down to the same thing internally):

    resource.addObserver(foo)

    resource.addObserver(fancyIndicator, owner: foo)

    resource.addObserver(owner: foo) {
        resource, event in
        updateStuff(resource.latestData)
    }

Oh, that's an interesting API. I think it's pretty unusual that the
direct object of the method is a trailing closure, and IMO inventing
some conventions for handling this kind of API in your own code would be
perfectly appropriate.

The API guidelines as stated would have us change that last one to:

    resource.addObserverWithOwner(foo) {
        resource, event in
        updateStuff(resource.latestData)
    }

However, this incorrectly implies that there is a distinct kind of
thing that is an “observer with owner,” and that we will get one only
from the third flavor of the method. That implication is wrong.

Yes, one of the complaints I have about the guidelines trying so hard to
avoid initial argument labels is that it causes some things to be read
as closely-associated when they should not be. The guidelines prevent us
from using that opening parenthesis to express a lack of association.

This comes up especially with Bool parameters, e.g.

  dismissAnimated(false)

where "animated" is essentially a parameter tuning the behavior of the
basic functionality, "dismiss," rather than an intrinsic part of that
functionality.

Others developing the API guidelines felt that the parenthesis was not
significant enough to be meaningful to people reading the call, and that
any increased expressivity was not paid for by the fact that the surface
of our APIs would be less-consistent (a more even balance of APIs with
and without initial labels is less consistent than having initial labels
be quite rare).

The consistency in the original of the “addObserver” name and the
“owner:” label make the correct implication: all three methods serve
the same purpose, observers are observers, and “owner” means the same
thing in the two places it appears. I certainly think the
non-compliant version of the code reads better.

+1

There was extensive discussion around another family of methods that
return a resource given either a path fragment or an absolute
URL. This is where we ended up:

    service.resource("/foo")
    service.resource(absoluteURL: "http://bar.com")
    service.resource(absoluteURL: NSURL(string: "http://bar.com"))

(The first is by far the most common, the “standard” flavor.)

Sorry, perhaps it should be obvious, but why do you need the label at
all here? Seems to me you could do this with two overloads, since it's
easy to detect when a string is an absolute URL.

The guidelines would have had us do this:

    service.resourceWithPathFragment("/foo")
    service.resourceWithAbsoluteURL("http://bar.com")
    service.resourceWithAbsoluteURL(NSURL(string: "http://bar.com"))

To my eyes, this crosses the line into verbosity that impedes clarity,

+1

but there’s an even more serious problem: it wrongly implies that
there’s a distinction between “resources with path fragments” and
“resources with absolute URLs.” That’s dangerously wrong. One of the
central conceits of the whole library is that _all_ resources get a
canonicalized absolute URL, and there’s a uniqueness guarantee for
that URL no matter whether it was constructed for a path fragment, an
absolute URL, or resource-relative navigation.

Yep, that's the "can't use ( to disassociate" problem again.

In the cases of both addObserver(…) and service.resource(…), the
guidelines would have us actively mislead users.

Another trickier example of the same issue is the much-discussed
typedContent method, which downcasts based on inferred type and
returns a default value if content is either missing or of the wrong
type:

    var image: UIImage?
    ...
    image = imageResource.typedContent(ifNone: placeholderImage)

How to make this conform to the guidelines? The obvious fix is
terrible:

    image = imageResource.typedContentIfNone(placeholderImage)

This implies … what? That the method only returns typed content if
there is none of the placeholder image?

Very similar to dismissAnimated.

No, clearly a rephrasing is necessary:

    image = imageResource.typedContentWithDefault(placeholderImage)

But again we have this problem of determining whether “with default”
describes the method’s behavior, its result, or its first
argument. Are we attaching content with the default somehow attached
to it? (No.) Are we returning some content, or a default value if
there is none? (Yes.) So maybe this is better:

    image = imageResource.typedContentOrDefault(placeholderImage)

But now my brain is having parsing problems. What is the LHS of that
“or?” It just doesn’t read naturally. OK, maybe even more words can
save us:

    image =
imageResource.typedContentOrDefaultIfNone(placeholderImage)

Yuck. At this point, we might as well stuff the entire method abstract
in the name:

    image =
imageResource.typedContentOrDefaultIfNoneOrMismatchedType(placeholderImage)

Yuck squared. The original is so much clearer:

    image = imageResource.typedContent(ifNone: placeholderImage)

Point taken, but if you let go of determining the return type by type
inference (pretty close to overloading on return type) you might be
better off.

      i = Image(foundIn: resource, default: placeholder)

IMO, there’s nothing wrong with leaning on programming language syntax
to help segment and clarify English syntax.

+1.

_______________________________

What’s the better guideline on first argument labels?

Radek had a nice thought in the aforementioned Gihub thread:

The rationale being, ifNone doesn't really describe the method … it
describes the parameter. Most of the time, the job of the method
makes the first parameter obvious (hence the guideline), but here, it
doesn't. So the parameter makes sense.

That echoes many of my thoughts.

I’ll give a +1 for these two recommendations from Erica, which run
along the same lines as Radek’s thought, but in more thorough detail:

Prefer external names for the first parameter when the natural
semantic relationship between the parameters is stronger than their
relation to the operation.

For example, the following calls use labels for the first parameter:

login(userName: "blah", password: "...")
moveTo(x: 50.0, y: 30.0)

This example is contrary to Swift's normal naming scheme which
integrates the first argument into the function or method name, for
example:

loginWithUserName("blah", password: "...")
moveToX(50.0, y: 30.0)

The coupling between x and y, username and password, (and yes it is a
judgement call) should be considered as a reason to employ an
external label.

Differentiate related calls whose implementations are distinguished
by their parameters, as you would with initializers, using first
parameter labels.

Instead of loginWithUserName("blah", password: "...") and
loginWithCredential(myCredential),
prefer:

login(userName: "blah", password: "...")
login(credential: myCredential)

I’m not sure we’ve found the perfect, crisp way of saying all this —
but I strongly agree that the existing guidelines are too rigid on the
question of the first arg label, and Erica’s wording comes the closest
I’ve seen to being a viable replacement.

I have a few problems with the above wording, but I'm all for loosening
the restriction. Unfortunately, getting the wording right isn't the big
challenge; the challenge is convincing the people that matter that the
increased expressivity of allowing first argument labels in more places
is worth the increased non-uniformity of APIs. Having examples like the
ones you've presented here should be very helpful.

Thanks,

···

on Sun Jan 24 2016, Paul Cantrell <swift-evolution@swift.org> wrote:

On Jan 23, 2016, at 6:33 PM, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote:

--
-Dave

This all looks good to me (aside from the linguistic problems with
verb conjugation I've raised in another subthread). However, I think
these naming guidelines lead us to reconsider our default argument
labeling rules for 'func' declarations again, as David Owens and
others have suggested. The stated goal of the current language rule is
to guide people into good API design following our conventions, but I
don't think it succeeds in serving that purpose. If you follow the
guidelines, the argument labels for your secondary arguments generally
end up becoming prepositional phrases, which make for poor variable
names,

Hi Joe,

Like Doug, I disagree that we guide you into using prepositional phrases
for secondary arguments. But I really want to address the "poor
variable names" part of what you said. It's true, as far as it goes,
but one thing nobody knows is that there are a few more guidelines
planned that didn't make it out in time for the review. One goes
something like this:

   Choose parameter names to serve your documentation comment. These
   names are not API, but they still matter. Well-chosen names allow
   the summary to read smoothly and to fully-describe the API in just a
   few words.

The main audience for the argument label is the reader of the use-site,
while the main audience for the parameter name is the reader of the
documentation and declaration. Therefore, they should often be
distinct, and whether an argument label makes a good parameter name is
mostly immaterial.

and you're naturally guided to giving the argument an explicit
descriptive binding name:

func perform(stuff: Stuff, with: Thing) {
  with.apply(stuff) // 'with' is a weird variable name
}

func perform(stuff: Stuff, with thing: Thing) {
  thing.apply(stuff) // 'thing' is better
}

The shorthand thus doesn't save the good API citizen from much
work.

True!

On the other hand, a developer who's unaware or uninterested in the
guidelines and is just trying to C or Java in Swift gets argument
labels by default that neither follow the guidelines nor meet their
expectation:

func atan2(y: Double, x: Double) -> Double { ... }

atan2(10, 10) // Why doesn't this work?
atan2(10, x: 10) // Nobody wants this

And when staring down potentially dozens or hundreds of compile errors
at various mismatched use sites,

That apocalyptic-sounding scenario went by too fast for me to imagine
how it actually arises. Care to spell that out?

they're unlikely to reconsider their API naming choice, and will
instead do the minimal amount of work to get their code to compile by
suppressing the argument label. The language hasn't led this developer
to better conventional API design either.

I can think of a couple possible modifications to the language rule
that could help reduce the surprise factor, and still lead people to
good API design:

I'm all for having a discussion of different language rules, but let's
keep them in a separate thread, please!

···

on Sat Jan 23 2016, Joe Groff <swift-evolution@swift.org> wrote:

--
-Dave

My line of thinking is a close variant of this. Usually if I think of the arguments as a potential data structure I pass into the function, then I name the function as if I was passing them all as a single unlabelled argument.

Usually I think of this as a tuple, so I’m not distracted by whether or not a formal type is needed.

examples (which work today!):

let origin = (x: 0.0, y:0.0)
func moveTo(x x: Double, y:Double) { print("moved to (\(x), \(y))") }
moveTo(origin)

let userCredentials = (username:”jdoe", password:”abcd1234”)
func logInWith(username username:String, password:String) -> Bool { return true }
logInWith(userCredentials) // my preferred name, since you are giving access to a user and not to credentials

-DW

<snip>

···

On Jan 24, 2016, at 1:23 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:
Radek had a nice thought in the aforementioned Gihub thread:

The rationale being, ifNone doesn't really describe the method … it describes the parameter. Most of the time, the job of the method makes the first parameter obvious (hence the guideline), but here, it doesn't. So the parameter makes sense.

I’ll give a +1 for these two recommendations from Erica, which run along the same lines as Radek’s thought, but in more thorough detail:

On Jan 23, 2016, at 6:33 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Prefer external names for the first parameter when the natural
semantic relationship between the parameters is stronger than their
relation to the operation.

For example, the following calls use labels for the first parameter:

login(userName: "blah", password: "...")
moveTo(x: 50.0, y: 30.0)

This example is contrary to Swift's normal naming scheme which integrates the
first argument into the function or method name, for example:

loginWithUserName("blah", password: "...")
moveToX(50.0, y: 30.0)

The coupling between x and y, username and password, (and yes it is a judgement call)
should be considered as a reason to employ an external label.

Differentiate related calls whose implementations are distinguished by their
parameters, as you would with initializers, using first parameter labels.

Instead of loginWithUserName("blah", password: "...") and loginWithCredential(myCredential),
prefer:

login(userName: "blah", password: "...")
login(credential: myCredential)

I’m not sure we’ve found the perfect, crisp way of saying all this — but I strongly agree that the existing guidelines are too rigid on the question of the first arg label, and Erica’s wording comes the closest I’ve seen to being a viable replacement.

Cheers,

Paul

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Some of the particulars of the guidelines haven’t worked well for me in practice — and I see from this thread that others have hit some of the same problems.

In short, in a real-world project, pre-guidelines code agreed with the guidelines 89% of the time, but where it disagreed, the guidelines achieved only a 25% acceptance rate with the curmudgeonly developers.

You can follow that discussion here:

  Siesta API guidelines audit.md · GitHub
  https://github.com/bustoutsolutions/siesta/issues/15…
I’ll share in a separate message some notes on the other places where we rejected the guidelines on questions other than the first arg label.

Here is that separate message as promised, with real-world examples of where the guidelines didn’t seem right for Siesta for reasons other than first arg naming.

Interestingly, all of them are part-of-speech questions. I’m intentionally writing up these notes before perusing Erica’s grammar writeup, so I can capture the raw reactions before letting them be colored by that document. Erica, I’ll get to your doc soon!

···

On Jan 24, 2016, at 2:23 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

_____________

Siesta uses the widespread fluent style of attaching callbacks to a request:

    resource.load()
        .onCompletion { _ in stopSpinnyThing() }
        .onSuccess { _ in showHappyFace() }
        .onFailure { _ in showSadFace() }
        .onNewData { _ in soundTrumpets() }

These methods mutate the receiving request (by adding a callback), and the guidelines thus say that they should be named as imperative verbs. The results of that don’t seem like an improvement:

    resource.load()
        .addCompletionCallback { _ in stopSpinnyThing() }
        .addSuccessCallback { _ in showHappyFace() }
        .addFailureCallback { _ in showSadFace() }
        .addNewDataCallback { _ in soundTrumpets() }

In a related case, it’s possible to attach a callback to be run before any request within a given context:

    $0.config.beforeStartingRequest {
        _ in performDrumroll()
    }

It’s not even clear to me what the imperative verb here should be. Maybe “callBeforeStartingRequest”? The guideline-conforming options are all awkward; the guideline-breaking form above is clear.

I’d suggest a rule along these lines (but with less convoluted phrasing, if anyone can figure that out):

“When a method’s last argument is a closure, the method’s name and other arguments may read as a clause which modifies the closure as if it were a sentence with an imperative verb.”

Um, yeah, mouthful. Examples may help:

  Before starting a request, ← method
  perform a drumroll. ← closure

  On completion, ← method
  stop the spinny thing. ← closure

____

The ResourceObserver protocol, which clients will implement frequently, consists of “response to event” methods that may or may not mutate the receiver, but probably have side effects. These are methods clients will implement, but probably not call. An example:

    func resourceChanged(resource: Resource, event: ResourceEvent) {
        tableView.reloadData()
    }

The name “resourceChanged” feels right to me. The old-school Cocoa name would be resourceDidChange, which also feels OK. Options that are strictly nouns or verbs — resourceChange, respondToResourceChange — all feel awkward by comparison.

I think this has something to do with the “responding to event” nature of the method, crossed with the fact that it’s named in a protocol. We can’t know what it does, so we it doesn’t make sense to describe it as a verb. We only know why it’s called, what situation it’s responding to.
____

On the other side of the verb/noun coin, the ResponseTransformer protocol consists of a single method…

    public protocol ResponseTransformer {
        @warn_unused_result
        func process(response: Response) -> Response
    }

…which is purely functional — should mutate neither the receiver nor the argument — yet just really, really seems wrong to me if it’s not named “process.” Why? I don’t have a rule. My gut just tells me that method should be a verb.

____

Last up, the rule that all enum cases should be nouns didn’t seem to fit here:

    public enum ResourceEvent: CustomStringConvertible {
        case ObserverAdded
        case Requested
        case RequestCancelled
        case NewData(NewDataSource)
        case NotModified
        case Error
    }

Noun alternatives such as “ObserverAddition” and “RequestStart” somehow come with more mental friction.

Again, I don’t have a rule to propose here — and in these cases, we may just have to say “this is why guidelines are guidelines, not laws,” and leave it at that. Or someone can propose better names, which would be awesome!

Cheers,

Paul

What is the rationale behind naming enumeration cases in upper camel
case?

Apparently, among those to whom that convention feels right, it's
because enums in Swift are often used to express what in ObjC would be
global constants, and on Apple platforms those global constants have
"always" started with an uppercase letter. So if we want to change the
way it's done, that's the point-of-view we need to grapple with.

···

on Sat Jan 23 2016, Marc Knaup <swift-evolution@swift.org> wrote:

*Follow case conventions:* names of types, protocols and enum cases are

UpperCamelCase. Everything else is lowerCamelCase.

let a = NSComparisonResult.OrderedSame // refers to a value, but is
upper-case
let b = NSDate.distantFuture // refers to a property/value, but
is lower-case

   - everything related to types (type names, protocol names, generic type
   parameter names) should be upper camel case
   - everything else (function names, property names, variable names, etc.)
   should be lower camel case

This is already the current and the proposed recommendation with
enumeration cases being the only exception.
Enumeration cases are not types.

On Fri, Jan 22, 2016 at 10:02 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:

Hello Swift community,

The review of SE-0023"API Design Guidelines" begins now and runs through
January 31, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

Reviews are an important part of the Swift evolution process. All reviews
should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the
review manager. When replying, please try to keep the proposal link at the
top of the message:

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

Reply text

Other replies

<GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
goes into a review?

The goal of the review process is to improve the proposal under review
through constructive criticism and, eventually, determine the direction of
Swift. When writing your review, here are some questions you might want to
answer in your review:

   - What is your evaluation of the proposal?
   - Is the problem being addressed significant enough to warrant a
   change to Swift?
   - Does this proposal fit well with the feel and direction of Swift?
   - If you have used other languages or libraries with a similar
   feature, how do you feel that this proposal compares to those?
   - How much effort did you put into your review? A glance, a quick
   reading, or an in-depth study?

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Doug Gregor

Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

Cross-linking to an interesting discussion in SE-0005 about adding a heuristic to split the method name and an explicit first argument label by the word “with”:

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/007874.html
— Radek

···

On 25 Jan 2016, at 19:07, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ooookay, this thread took *a while* to go through. Phew!

Echoing from my reviews of SE-0005 and SE-0006:

I’m overwhelmingly *for* this proposal. I think removing needless verbosity and keeping the signal-to-noise ratio high is one of the most immediately appealing aspects of Swift, as well as a great general improvement to the programming experience.

And these guidelines do a great job at this. Like Paul Cantrell said, they recognize that both verbosity and brevity endanger clarity of code, and present many formalized rules to try to strike a balance in between, and keep S/N high. Both by reminding writers (yes, software writers!) to be explicit when it’s important, and by getting rid of noise that conveys little to no information, especially in a statically-typed language.

Although the API Design Guidelines sometimes err slightly more on the side of explicitness than me, I’m +1 aside from some concerns below:

* * *

= Prefer to follow the language’s defaults for the presence of argument labels =

This has been extensively discussed in this thread, by Erica, Paul, Dave, and others, so apologies if I repeat arguments already made, but:

I think there are more use cases where it makes sense to make the first argument label explicit than the guidelines consider.

The way I see it, most of the time, the method name, its fundamental job describes the first parameter, or makes it obvious. And so, the default behavior of Swift, and the general guideline are correct. However, there are cases, where this isn’t so.

   addObserver(foo)

Here, the method name says what first argument it takes right on the box. And `add(observer: …)` wouldn’t be appropriate, because this isn’t some general, generic “add”. The method adds an observer in particular. It’s fundamentally what it does, so it goes on the name.

   array.contains(“foo”)

This doesn’t describe the parameter explicitly, but the parameter is obvious, and makes something of a “sentence”. No label needed.

   login(username: “foo", password: “bar")

Here, “username” should _not_ be part of the name, because it doesn’t describe the fundamental job of the method. The method logs you in. Username is just a parameter.

One way to think about it, as Erica pointed out, is that the parameters are bound more strongly together than “username” is to the name. Another way to think about it, it would be completely natural to make the parameters a standalone tuple or a separate type:

   let credentials = (username: “foo”, password: “bar”)
   login(credentials)
   // or:
   login(LoginPair(username: “foo”, password: “bar”))

Another way in which it makes sense, and again this was pointed out, is that if you have multiple ways of logging in, it’s still logging in:

   login(username: “foo”, password: “bar”)
   login(token: “asdfg”)

Making the names “loginWithUsername” and “loginWithToken”:

- looks weird if you’re not used to Objective-C
- is unnecessarily verbose (tiny thing, but “with” conveys zero information, so I’d prefer to rely on Swift’s punctuation and make it an explicit parameter label)
- makes it seem as if the two methods were fundamentally different things, and they’re not. They’re two variants of the same method, so they should have a common name, and different parameters.

More examples:

   moveTo(x: Double, y: Double)

This passes multiple of the previous tests. “x” is a parameter, has nothing to do with the method itself. It could just as well be a tuple or a separate type. And if you had a different way of passing the position data, you’d still want the same name.

   constructColor(red: 0.2, green: 0.3, blue: 0.1)

Same thing.

An example from SE-0005 I proposed: [swift-evolution] [Review] SE-0005 Better Translation of Objective-C APIs Into Swift
   func fill(blendMode: CGBlendMode, alpha: CGFloat)
   func stroke(blendMode: CGBlendMode, alpha: CGFloat)
   func encode(coder: Coder)
Copying and pasting what I said in that thread:

Again, the method, the action itself (“fill”, “stroke”, “encode”) doesn’t naturally describe the first parameter in a way “insert” on a collection, or “addObserver” would. The blend mode and coder values here are merely _options_ of the method, not its _fundamental job_.

One way to conceptualize the difference is to think of arguments as being either “inputs” or “options”. A passed element to be inserted to a collection is an input, but blend mode is only an option of a fill, an operation that conceptually takes no inputs.

(I also don’t believe that “don’t repeat type information” rule applies here. “blend mode” is a description of the parameter, not only its type. Same with coder. We’re not needlessly repeating type information here, we’re describing option parameters, which happen to be the same as type names.)

I think the language defaults and general guidelines are good. But the guidelines should be slightly more open about other situations where overriding the default is clearer to the reader.

* * *

= Omit Needless Words =

One more example to the parameters discussion, and also related to omitting needless words:

   array.joinWithSeparator(“,”)

I have multiple problems with this API. First of all, this should be, in my mind:

   array.join(separator: “,”)

because “separator” is a parameter, not the description of the method itself.

(In fact, I would go as far as to say `array.join(“,”)` because it seems always obvious from context.)

But aside from that, I take issue with this pattern because of the word “with”. This is a needless word that should be omitted. It contains no information. It’s just syntactic glue, which is not necessary here since we can say `join(separator: …)` instead.

(A rule of thumb: If you’re tempted to write `fooWithBar(…)`, you probably should use `foo(bar:)`, just like `initWithFoo:` from ObjC is translated to `init(foo:)`)

And I see that in many places. Not much in Swift, but a lot more in Objective-C APIs. Needless words like “with”, “and”, “by”, “using”, “for". I’m not saying they’re always unnecessary; they often help convey the semantics or intent, or are needed for the method name to make sense. Or sometimes they replace a noun in describing a parameter (see: stride). But too often they’re just glue words used to make code sound like English without any actual readability benefits, and merely adding noise.

Sorry about this mini-rant. I’m not sure if this requires additional examples or clarification in the Guidelines text aside from the first-parameter discussion, but something I wanted to point out.

* * *

= If the first parameter of a method is defaulted, it should have an argument label. =

Okay, I think you all got the idea by now, but I can’t help myself. This rule says you should do something like:

   mutating func removeAll(keepingCapacity keepingCapacity: Bool = false)
   close(completionHandler completion: ((Bool) -> Void)? = nil)

But consider what would happen if these parameters weren't defaulted, for whatever reason:

It would still make more sense to say:

   removeAll(keepingCapacity: false)
   close(completionHandler: { … })

Than:

   removeAllKeepingCapacity(false)
   closeWithCompletionHandler({ … })

This suggests to me that this rule is not fundamental, rather it derives from the distinction between the implied function input and method options/parameters I discussed earlier. The use case with default values is just the most common example of this in practice, since “options” (vs inputs) very often have a sensible default.

* * *

= -ed / - ing / -inPlace =

I have nothing to add others haven’t, but I agree that these rules are still really awkward.

* * *

I haven’t found any other serious issues with the proposal. I have some ideas to _add_ to the Guidelines, but I figure those can wait and should get their own thread later. The overall language and spirit is exactly what I was hoping for.

And just don’t forget:

Good APIs aren't the result of
applying a set of mechanical rules. You have to consider what the usage
will look like.

(Dave Abrahams)

These are guidelines, not the law. It’s a great thing to have a set of guidelines applicable in 95% of cases, and have the community consistently apply them, but there’s always room for good judgement along the edges.

Best,
— Radek

On 22 Jan 2016, at 22:02, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of SE-0023"API Design Guidelines" begins now and runs through January 31, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md
Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the review manager. When replying, please try to keep the proposal link at the top of the message:

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md
Reply text

Other replies
<GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Proposal link:
https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

What is your evaluation of the proposal?

I think there are more things which would make a "guidelines" document
even
better for promoting consistent code:

- When to use functions vs. properties for getters. The changes in
SE-0006
<https://github.com/apple/swift-evolution/blob/master/proposals/0006-apply-api-guidelines-to-the-standard-library.md&gt;
include
"func min()" and "var underestimatedCount". SE-0005
<https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md&gt;
includes "class func darkGray()". I imagine it should be implied that
properties are more efficient to compute, but this doesn't seem to be
applied consistently.

I'm glad you mentioned this, Jacob. We had extensive internal
discussions about properties, and made substantial progress, but we do
not yet have wording suitable for the guidelines. Let me tell you where
things stand.

,----[ Side Note, since you mentioned efficiency ]

I originally wanted to uphold the principle that, “if it isn't O(1), you
don't make it a property.” The implication is that on collections,
“count” would be a method. That would include Array, for which counting
the elements *is* O(1). Some people argued that:

1. The idea of writing “a.count()” instead of “a.count” to count the
   elements of an Array was absurd.
2. Programmers don't draw conclusions about efficiency based on whether
   something is a property.
3. The fact that Array would have an O(1) non-property that *could* have
   been a property (if it weren't for CollectionType conformance)
   undermines any communicative power that you might get from using this
   distinction to choose properties.

I did not win that argument :-)

`----

So we surveyed the entire standard library, trying to arrive at some
consensus about what ought to be a property and what ought not to be
one. Fortunately I happen to already have a write-up of those results:

The parts I'm not currently satisfied with are:

1. I don't know how to nail down what was meant by “intrinsic” in:

     Things that are “intrinsic” to the receiver are properties

2. (possibly-related): The following don't seem (to me) to be a clear
   fit for any of the criteria. I think we made the right decision in
   most cases, but I don't know how to describe why:

   * description, debugDescription, customReflectable.customMirror
   * first
   * unsafePointer.pointee
   * string.utf8.nulTerminatedUTF8
   * collection.min()
   * sequence.iterator()

3. I don't understand the rationale we currently have for
   sequence.iterator() not being a property, even though I think that's
   the right choice.

I *do* think there's enough here to eventually turn it into wording for
the guidelines, but it's going to take a little more work. If the
community can help us clarify the points above, I'm sure it could be a
big help!

Cheers,

···

on Sat Jan 23 2016, Jacob Bandes-Storch <swift-evolution@swift.org> wrote:

--
-Dave

Proposal link:
https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

What is your evaluation of the proposal?

I think there are more things which would make a "guidelines" document
even
better for promoting consistent code:

- When to use functions vs. properties for getters. The changes in
SE-0006
<https://github.com/apple/swift-evolution/blob/master/proposals/0006-apply-api-guidelines-to-the-standard-library.md&gt;
include
"func min()" and "var underestimatedCount". SE-0005
<https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md&gt;
includes "class func darkGray()". I imagine it should be implied that
properties are more efficient to compute, but this doesn't seem to be
applied consistently.

Separately replied to the above, continuing with the rest

- Edge cases of naming, such as what to do with acronyms (like URL)
when they appear in function and variable names, especially at the
beginning.

This is something that was still under discussion internally when the
review started. The argument internally has been between whether to:

1. Always capitalize the whole initialism, even in variable and method
   names.
2. Capitalize or lowercase the whole initialism according to case
   conventions (e.g. in a type name it would be all-caps).

Some people in this group have expressed a strong preference for another
possibility, which IIUC is “All but the first letter of the initialism
are lower-case; capitalize according to case conventions,
i.e. no-special-treatment."

- When to use structs/classes/enums; when to use optionals; other such
basic API design topics.

Hmm, I'm not sure whether that's in scope for this document.

While certainly not everything from the Coding Guidelines for Cocoa
<https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html&gt;
(linked from SE-0005) applies to Swift, the Swift guidelines would do
well
to match its thoroughness.

When I look at that document, the section titles at least imply it's
*only* about naming and not about any of those other things you just
mentioned.

    Protocols that describe what something is should read as nouns
(e.g.
Collection).
    Protocols that describe a capability should be named using the
suffixes
able, ible, or ing (e.g. Equatable, ProgressReporting).

"SetAlgebra" (from SE-0006) doesn't really fit in with this.

It arguably fits in with the former, but I agree it's not a perfect
fit. If you have better suggestions, I'm all ears.

Extremely minor:
    text = "The value is: "
    text += String(veryLargeNumber)
    text += " and in hexadecimal, it's"
    text += String(veryLargeNumber, radix: 16)

The second string literal should have a space at the end as well as
the
beginning.

Thanks!

···

on Sat Jan 23 2016, Jacob Bandes-Storch <swift-evolution@swift.org> wrote:

--
-Dave

My evaluation is inline below...

Thanks for your review, Patrick!

Hello Swift community,

The review of SE-0023"API Design Guidelines" begins now and runs
through January 31, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md
<https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md&gt;
Reviews are an important part of the Swift evolution process. All
reviews should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the
review manager. When replying, please try to keep the proposal link
at the top of the message:

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md
<https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md&gt;
Reply text

Other replies
<GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. goes into a review?

The goal of the review process is to improve the proposal under
review through constructive criticism and, eventually, determine the
direction of Swift. When writing your review, here are some
questions you might want to answer in your review:

What is your evaluation of the proposal?

Overall, I like the proposal. It provides sound guidance that can lead
to consistent code in practice. However, there are some issues and
concerns I have:

- Under "Fundamentals", there is a bullet called "Write a
documentation comment...". Under this bullet, this is another bullet
called "Use a single sentence fragment...". Why?

Because it leads to a concise, readable summary that works well with
tools and often fully describes the API. It is also easy to do. It's
crucial that the most important part of the documentation is also easy
to produce, or people won't do it.

I find sentence fragments often detract from clarity and concise
nature, which can lead to confusion.

We have lots of examples that follow this style in the Swift standard
library. Can you point at some that are confusing, unclear, or not
concise because they use sentence fragments?

- Under "Naming", there is a bullet called "Omit Needless Words". This
bullet states, "Occasionally, repeating information is necessary to
avoid ambiguity..." It would be useful to provide an example that the
reader can use to disambiguate this use case.

Point taken.

- Under "Naming", there is a bullet called "Compensate for Weak Type
Information...". The example provided is confusing. First, it
contradicts the guidance relating to omitting needless words. It
suggests that

func add(observer: NSObject, for keyPath: String)

becomes

func addObserver(_ observer: NSObject, forKeyPath: String)

This results in "Observer" followed by "observer". Why is this more
clear?

Because it's not the declaration site that matters; it's the use site.

Just to take the first use-site I could find with GitHub search, imagine
the code at

said "add" instead of "addObserver". Would it make sense?

In addition, I don't understand why it collapsed "for keyPath" to
"forKeyPath". Perhaps an explanation would clarify?

Again, because it's the use-site that matters. With "for keyPath", at
the use-site, you'd only see "for".

- Under "Naming", there is a bullet called "Uses of non-mutating
methods should read as noun phrases...". This bullet provides an
example of an exception. Why would calling this method firstAndLast()
have less clarity than split()?

Because, among other things, "firstAndLast" incorrectly implies you only
get two parts back.

Perhaps a better example is in order.

Suggestions welcomed.

- Under "Naming", there is a bullet called "When a mutating method is
described by a very, name its non-mutating counterpart...". On the
surface this appears to provide good guidance, I think in practice it
becomes difficult and doesn't necessarily provide the desired
result. I think Ruby provides a better example of how the desired
result is very clear. In Ruby, the name of a mutating method is
designated by an exclamation point at the end of the name.

Yes, but we don't have the necessary language features
(e.g. https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst\)
to do something like that today, so we need to use a naming convention
instead.

For example, myString.reverse() returns the value of the reversed
string, while myString.reverse!() mutates myString with the reversed
value. I'm not necessarily proposing that Swift use the exclamation
point for this purpose (as Swift already uses this force unwrapping),
so much as I'm proposing that you investigate how other languages
clearly disambiguate non-mutating and mutating methods.

- Under "Conventions", there is a bullet called "Methods can share a
base name when they share the same basic meaning...". There are some
examples when this convention does not apply.

Example, please? I have no idea what you might be referring to.

I think it would be helpful to illustrate to the reader how to address
these exceptions (i.e., do this, instead of that).

- Under "Conventions", there is a bullet called "Prefer to follow the
language's defaults for the presence of argument labels". Be aware
that the current compiler issues the warning when the first argument
label is "_", "Extraneous '_' in parameter: <parameter> has no keyword
argument name". I would either like the compiler to not issue a
warning for this use case, or at least give the developer the means to
disable this warning.

I understand. I don't think your request will get the traction you'd
like if you don't expose it somewhere other than in this thread. We're
not considering new language rules here.

···

on Fri Jan 29 2016, Patrick Gili <swift-evolution@swift.org> wrote:

On Jan 22, 2016, at 4:02 PM, Douglas Gregor <dgregor@apple.com> wrote:

Is the problem being addressed significant enough to warrant a change to Swift?

I think publishing a clear set of guidelines is absolutely necessary.

Does this proposal fit well with the feel and direction of Swift?

Absolutely. Great job!

If you have used other languages or libraries with a similar
feature, how do you feel that this proposal compares to those?

I think all serious languages have a document that specifies a set of
guidelines with the intent of bringing consistency in the use of the
language. Languages that do not drive a set of best practices tend to
suffer, at least form a readability perspective. For as much as I like
Ruby, it lacks such a set of guidelines, which has resulted in the
community writing code that lacks the consistency that makes it easy
to read others' code.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

As always, I read the proposal multiple times, which included reading
through the guidelines multiple times, sleeping on it, pondering it,
and finally writing my evaluation.

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
<https://github.com/apple/swift-evolution/blob/master/process.md&gt;
Thank you,

-Doug Gregor

Review Manager

_______________________________________________
swift-evolution-announce mailing list
swift-evolution-announce@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution-announce

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

Overall, I like the proposal. It provides sound guidance that can lead to consistent code in practice. However, there are some issues and concerns I have:

- Under "Fundamentals", there is a bullet called "Write a documentation comment...". Under this bullet, this is another bullet called "Use a single sentence fragment...". Why? I find sentence fragments often detract from clarity and concise nature, which can lead to confusion.

This fragment is added to the name of the function so if you have a function named "myFunction", the descriptive fragment is "converts integers to strings." and the display is:

Description: myFunction converts integers to string.

Hi Erica,

This was in the documentation section, I didn't think this applied to the naming of functions/methods.

Cheers,
-Patrick

···

On Jan 29, 2016, at 11:11 AM, Erica Sadun <erica@ericasadun.com> wrote:

Overall, I like the proposal. It provides sound guidance that can lead to consistent code in practice. However, there are some issues and concerns I have:

- Under "Fundamentals", there is a bullet called "Write a documentation comment...". Under this bullet, this is another bullet called "Use a single sentence fragment...". Why? I find sentence fragments often detract from clarity and concise nature, which can lead to confusion.

This fragment is added to the name of the function so if you have a function named "myFunction", the descriptive fragment is "converts integers to strings." and the display is:

Description: myFunction converts integers to string.

- Under "Fundamentals", there is a bullet called "Write a
documentation comment...". Under this bullet, this is another bullet
called "Use a single sentence fragment...". Why?

Because it leads to a concise, readable summary that works well with
tools and often fully describes the API. It is also easy to do. It's
crucial that the most important part of the documentation is also easy
to produce, or people won't do it.

I find sentence fragments often detract from clarity and concise
nature, which can lead to confusion.

We have lots of examples that follow this style in the Swift standard
library. Can you point at some that are confusing, unclear, or not
concise because they use sentence fragments?

In a previous email, Erica explained well the intent of the guideline by expanding on it, providing a good example and a good "anti-example". I also spent some quality time with the standard library source and think I understand the intent: eliminating redundancy in the interest of maintaining focus.

- Under "Naming", there is a bullet called "Compensate for Weak Type
Information...". The example provided is confusing. First, it
contradicts the guidance relating to omitting needless words. It
suggests that

func add(observer: NSObject, for keyPath: String)

becomes

func addObserver(_ observer: NSObject, forKeyPath: String)

This results in "Observer" followed by "observer". Why is this more
clear?

Because it's not the declaration site that matters; it's the use site.

Just to take the first use-site I could find with GitHub search, imagine
the code at
https://github.com/phileggel/Hangman/blob/c14fbbfd06e58527832c0634785aee45cb9e5e13/SwiftHangman/View%20Controllers/HMViewController.swift#L11
said "add" instead of "addObserver". Would it make sense?

These terms, "declaration site" and "use site" are new to me. Could you please provide a brief explanation?

Nevertheless, the code that you have reference clarifies the point.

- Under "Naming", there is a bullet called "Uses of non-mutating
methods should read as noun phrases...". This bullet provides an
example of an exception. Why would calling this method firstAndLast()
have less clarity than split()?

Because, among other things, "firstAndLast" incorrectly implies you only
get two parts back.

My misunderstanding. I now see you were referring to String.split().

Perhaps a better example is in order.

Suggestions welcomed.

The example is fine, but confusing because it taken out-of-context. Maybe expand the example to read more like this:

let fullName = "Johnny Appleseed"
let firstAndLast = fullName.split()

- Under "Naming", there is a bullet called "When a mutating method is
described by a very, name its non-mutating counterpart...". On the
surface this appears to provide good guidance, I think in practice it
becomes difficult and doesn't necessarily provide the desired
result. I think Ruby provides a better example of how the desired
result is very clear. In Ruby, the name of a mutating method is
designated by an exclamation point at the end of the name.

Yes, but we don't have the necessary language features
(e.g. https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst\)
to do something like that today, so we need to use a naming convention
instead.

I like this proposal. However, it sounds like this is something that won't be in Swift 3?

For example, myString.reverse() returns the value of the reversed
string, while myString.reverse!() mutates myString with the reversed
value. I'm not necessarily proposing that Swift use the exclamation
point for this purpose (as Swift already uses this force unwrapping),
so much as I'm proposing that you investigate how other languages
clearly disambiguate non-mutating and mutating methods.

- Under "Conventions", there is a bullet called "Methods can share a
base name when they share the same basic meaning...". There are some
examples when this convention does not apply.

Example, please? I have no idea what you might be referring to.

I think it would be helpful to illustrate to the reader how to address
these exceptions (i.e., do this, instead of that).

My apologies, my thought was poorly expressed. Let me try again. The guideline provides some examples of when methods should not share a base name. For example,
extension Database {
  /// Rebuilds the database's search index
  func index() { ... }

  /// Returns the `n`th row in the given table.
  func index(n: Int, inTable: TableID) -> TableRow { ... }
}
A beginner is going to ask, "If this isn't what I'm supposed to do, then what is acceptable?" It might be useful to expand the guideline to help the beginner. This last example was somewhat obvious, but the next example is necessarily so obvious:
extension Box {
  /// Returns the `Int` stored in `self`, if any, and
  /// `nil` otherwise.
  func value() -> Int? { ... }

  /// Returns the `String` stored in `self`, if any, and
  /// `nil` otherwise.
  func value() -> String? { ... }
}

- Under "Conventions", there is a bullet called "Prefer to follow the
language's defaults for the presence of argument labels". Be aware
that the current compiler issues the warning when the first argument
label is "_", "Extraneous '_' in parameter: <parameter> has no keyword
argument name". I would either like the compiler to not issue a
warning for this use case, or at least give the developer the means to
disable this warning.

I understand. I don't think your request will get the traction you'd
like if you don't expose it somewhere other than in this thread. We're
not considering new language rules here.

Point taken.

It suddenly occurs to me it's almost the 31st and I haven't actually
responded to the proposal as a proposal.

Thanks for taking the time to do this, Erica. I'm going to take issue
with some of your feedback below, but please know this is motivated by a
desire to make the most of your contribution. I think your feedback is
valuable, but much of the signal is getting lost.

I heartily endorse a general set of API guidelines and I appreciate
this first approach towards satisfying that goal. I have issues with
two sections.

First, I'd entirely eliminate the guidance in the "Be Grammatical"
section and move the section with boolean assertions and property
names to Special Instructions.

I *think* I may know why you want to eliminate the first part, but I
have no clue why you think it'd be better to move the other part.
Statements like these don't really provide much useful feedback, because
we can't tell what problems you think you're solving.

* I disagree with the mutating/non-mutating differentiation. I started
writing about this here before personally abandoning it as too big a
question: Grammatical.md
<https://github.com/erica/SwiftStyle/blob/master/Grammatical.md&gt;\. In a
nutshell, side-effects and pure functionality are not considered the
way I'd want them to be and the ed/ing naming is problematic.

I still don't really understand this objection. I do believe that
generalizing beyond "mutating" to cover "anything with side-effects"
would improve the guideline quite a lot. I don't understand any of the
rest of your beef with this guideline.

* The protocol question is big and wide as well, and I have written
on-list: it's not "the role of a protocol to describe implementation
details...Going that way leads you to over-designated hungarian-esque
guidelines that I'd rather keep loose, friendly, and sensible."

You have written that, but nothing in the guidelines suggests describing
implementation details.

In "Conventions":

* I don't like endorsing that any property could or should not be O(1)
(vs recommending using a function instead)

We don't do that. We merely say that if it's not O(1) it should be
documented as such.

* The case convention for enumerations remains conventional without a
guiding principle. I'd rather have a firm "use lower camel case for
members" that I can complain about (because it feels to me like "pick
a type layout for this memory", so upper camel) rather than "use upper
camel and let everyone on the Swift team complain about it" once and
for all.

Understood.

* With regard to argument labels, I'd like to add two rules,

as detailed in-thread and written about here: ArgumentLabels.md
<https://github.com/erica/SwiftStyle/blob/master/ArgumentLabels.md&gt;

Differentiate related calls whose implementations are distinguished by
their parameters, as you would with initializers, using first
parameter labels. Instead of loginWithUserName("blah", password:
"...") and loginWithCredential(myCredential), prefer:

login(userName: "blah", password: "...")
login(credential: myCredential)
This approach emphasizes the action being taken (login) and demotes
the actual arguments involved in performing that action. In doing so,
they require labels to differentiate which implementation of that
action is to be used.

and

Prefer external names for the first parameter when the natural
semantic relationship between the parameters is stronger than their
relation to the operation.

That rule doesn't work for any one-parameter methods, unless you think
they should never have first argument labels.

For example, the following calls use labels for the first parameter:

login(userName: "blah", password: "...")
moveTo(x: 50.0, y: 30.0)
constructColor(red: 0.2, green: 0.3, blue: 0.1)

This example is contrary to Swift's normal naming scheme which
integrates the first argument into the function or method name, for
example:

loginWithUserName("blah", password: "...")
moveToX(50.0, y: 30.0)
constructColorWithRed(0.2, green: 0.3, blue: 0.1)

The relationships between (x, y), (username, password), and (red,
green, blue) are strong enough to allow you to make a judgement call
to employ an external label.

The following shows a counter-example.

addLineTo(p1, withWidth: 25.0)

In this call, the point and width have no natural
relationship. There's no reason to create an external label for the
first argument so this example follows the standard Swift call
approach.

Thanks again for your feedback, Erica. If you'd care to clarify any of
the points above, that'd be extra awesome.

···

on Fri Jan 29 2016, Erica Sadun <swift-evolution@swift.org> wrote:

--
-Dave

Overall I like the proposals but I do have comments on a few issues.

enum case capitalisation. I generally like the use of lowerCamelCase
names because they are not types. Types are determined at compile time
and the case (value) of an enum is only known at runtime. I have
already seen people get confused by expecting to be able to use
information about an enum value at compile time. I think normally
using upperCamelCase would increase the confusion between cases and
types.

I have flicked through the thread and there are some good interesting
discussions particularly about argument labels in different ways. I'm
not sure there are any specific changes I want to strongly back but
the current proposals are not the uniquely correct approach. If there
are substantial changes it would be good to run them through as a
proposal for changes on top of this one so that they get proper
review, the thread is huge and many people may have missed things that
they really care about.

Noted; thanks, Joseph.

···

on Sat Jan 30 2016, Joseph Lord <swift-evolution@swift.org> wrote:

Joseph

On 22/01/2016 21:02, Douglas Gregor via swift-evolution wrote:

Hello Swift community,

The review of SE-0023"API Design Guidelines" begins now and runs through
January 31, 2016. The proposal is available here:

    https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

Reviews are an important part of the Swift evolution process. All
reviews should be sent to the swift-evolution mailing list at

    https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the
review manager. When replying, please try to keep the proposal link at
the top of the message:

    Proposal link:

        https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

    Reply text

        Other replies

          <GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
          goes into a review?

The goal of the review process is to improve the proposal under review
through constructive criticism and, eventually, determine the direction
of Swift. When writing your review, here are some questions you might
want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a
    change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have used other languages or libraries with a similar
    feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick
    reading, or an in-depth study?

More information about the Swift evolution process is available at

    https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Doug Gregor

Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

An anecdote in support of Erica’s thinking in the ongoing Battle of the First Argument Labels:

I mentioned the ongoing swift-evolution debates to Bret Jackson, one of my Macalester colleagues — awesome developer, 3D / VR / HCI researcher, tons of C++ experience, never seen Swift before — and typed out this example for him:

  moveTo(1.0, y: 0.5)

…and then this (he nods approvingly):

  moveTo(x: 1.0, y: 0.5)

…and then this:

  moveToX(1.0, y: 0.5)

…at which point, before I’d even finished typing it out, he physically recoiled in revulsion, threw hand up in front of his face, and let out a pained “oh please no!!” I wish I had video of him squirming in his chair. It was something to behold.

Thus my N=1 study of Swift newcomers concludes that “moveToX” is horrifying.

Cheers,

Paul

···

On Jan 29, 2016, at 10:29 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Differentiate related calls whose implementations are distinguished by their parameters, as you would with initializers, using first parameter labels.

Prefer external names for the first parameter when the natural semantic relationship between the parameters is stronger than their relation to the operation.

For example, the following calls use labels for the first parameter:

    login(userName: "blah", password: "...")
    moveTo(x: 50.0, y: 30.0)
    constructColor(red: 0.2, green: 0.3, blue: 0.1)

This example is contrary to Swift's normal naming scheme which integrates the first argument into the function or method name, for example:

    loginWithUserName("blah", password: "...")
    moveToX(50.0, y: 30.0)
    constructColorWithRed(0.2, green: 0.3, blue: 0.1)

The relationships between (x, y), (username, password), and (red, green, blue) are strong enough to allow you to make a judgement call to employ an external label.

Proposal link:

What is your evaluation of the proposal?
+1

I read the guidelines and I like them a lot in general. I think they are a very good start.

I have read the alternatives and disagreements in the discussion threads. However, in my opinion the guidelines still stand as the winner. I find it better, simpler, more concise and better looking than the alternatives discussed.

For example the ed/ ing ending for non-mutable methods. This is a convention I have used in java for a long time and I found it very natural in general even when the English language may not cooperate as it has been discussed by others. I got used to this convention very quickly many years ago in libraries I use in java.

There is only one guideline that I think is not aligned with the consensus I seem to pick up from the discussions. That is the use of camel case for enum cases. After reading different opinions I am now leaning towards saying that Enum cases should be lower camel case given that they are values. At first my opinion was the same as the guideline. After reading the discussions and seeing examples I changed my mind.

Is the problem being addressed significant enough to warrant a change to Swift?
This will bring a lot of changes when applied. I think they are a good start. I don't think it should cover all cases.

I saw the loginWithUserName(_:password:) example and alternatives: login(userName:password:), etc. I don't know if this is addressed in the guidelines. I don't think this example falls under the weak type first argument. It would be nice to have some guidance here. I do not know how to state it but I think in this case I would say login(userName:password:) is better as it could be part of a family of login() methods that take different parameters, i.e. credentials.

Does this proposal fit well with the feel and direction of Swift?
Definitely. I find the guidelines are concise, natural and easy to get used to.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
I have used Java libraries for many years that use the ed ending for non-mutable methods for example.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
I read the proposal entirely and I have read the majority of responses in the mailing list.

supportsVideoMirroring -> isVideoMirroringSupported
supportsVideoOrientation -> isVideoOrientationSupported

IMHO, for this particular case, I think the ones on the left read more as assertions about the receiver than the alternatives on the right.
I may be wrong, but I did not interpret this guideline as having to prefix boolean properties with is. I think these two would be fine as supportVideMirroring and supportVideoOrientation as they read as assertions about the receiver.

···

On Feb 1, 2016, at 2:51 AM, Colin Cornaby via swift-evolution <swift-evolution@swift.org> wrote:

I’m still processing all my thoughts on this and might have a thought or two on the Obj-C bridging thread as well, but I had a question about one specific style guideline:

Uses <> of nonmutating Boolean methods and properties should read as assertions about the receiver, e.g. x.isEmpty, line1.intersects(line2)

I have really mixed feelings on this, and was wondering what the rationale was (maybe to convince me it’s a good idea.) To me, this seems like adding extra language to a proposal that is pretty good at removing now unnecessary language. It also seems unhelpful to me as an API user and writer because in an alphabetical list, related functionality (like a “playing” nonmutating property and a “play” function, or a “playRate” mutable property) are all going to be moved away from each other in a list. I acknowledge that Xcode’s autocomplete is getting better though in that regard, and that most documentation is grouped. But I’m not a fan of the crowding of “is” functions that is going to happen.

In reviewing AVFoundation specifically (but I’m going through the others as well), I’m not sure this is an improvement either.

Mildly worse, makes it sound like a function instead of a property:
exposurePointOfInterestSupported -> isExposurePointOfInterestSupported

Same sort of thing, I’m not sure this is cleaner:
supportsVideoMirroring -> isVideoMirroringSupported

This one almost sounds to me like the function meaning is being tweaked:
videoMirrored -> isVideoMirrored

The name of this one now sounds like it is supposed to have an argument to check to see if a specific video orientation is supported (although it is true that the original property wasn’t named great either):
supportsVideoOrientation -> isVideoOrientationSupported

Like I said, I’d be willing to be talked into this, but at this point I’m just really curious what the justification is. For simple cases this seems to work well, but I’m really not enthused for what this does to more complex or domain specific property names. I’m willing to call this “unease after doing Obj-C too long”, but I’d like to understand why the Swift team feels this is better.

On Jan 22, 2016, at 1:02 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of SE-0023"API Design Guidelines" begins now and runs through January 31, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md
Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the review manager. When replying, please try to keep the proposal link at the top of the message:

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md
Reply text

Other replies
<GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m still processing all my thoughts on this and might have a thought
or two on the Obj-C bridging thread as well, but I had a question
about one specific style guideline:

Uses <> of nonmutating Boolean methods and properties should read as
assertions about the receiver, e.g. x.isEmpty,
line1.intersects(line2)

I have really mixed feelings on this, and was wondering what the
rationale was (maybe to convince me it’s a good idea.) To me, this
seems like adding extra language to a proposal that is pretty good at
removing now unnecessary language. It also seems unhelpful to me as an
API user and writer because in an alphabetical list, related
functionality (like a “playing” nonmutating property and a “play”
function, or a “playRate” mutable property) are all going to be moved
away from each other in a list.

The classic example is:

    x.empty()

does this clear the elements of x, or just tell you whether it has any?

Lisp users have a "-p" (for "predicate") suffix they append to things to
solve this kind of problem.

I acknowledge that Xcode’s autocomplete is getting better though in
that regard, and that most documentation is grouped. But I’m not a fan
of the crowding of “is” functions that is going to happen.

If that's going to be an issue, we should fix the tools.

In reviewing AVFoundation specifically (but I’m going through the
others as well), I’m not sure this is an improvement either.

Mildly worse, makes it sound like a function instead of a property:
exposurePointOfInterestSupported -> isExposurePointOfInterestSupported

Heh, I'd go with

    supportsExposurePointOfInterest

myself.

Same sort of thing, I’m not sure this is cleaner:
supportsVideoMirroring -> isVideoMirroringSupported

x.supportsVideoMirroring is how it should read. Did we make that change
automatically? Oh, I see, this came from
https://github.com/apple/swift-3-api-guidelines-review/commit/a6ce38eec58e8c2da901d0049a04e4b875c403b2\.

This is one of the rare cases where the original property name works
better than the getter. Looking at the rest of this change, it's IMO so
overwhelmingly positive that we'd want to just let the framework author
tweak this one explicitly with an NS_SWIFT_NAME annotation.

This one almost sounds to me like the function meaning is being tweaked:
videoMirrored -> isVideoMirrored

Well, I'd agree that videoIsMirrored or mirroring would be better names
in this case, but I don't think the transformation does any damage.

The name of this one now sounds like it is supposed to have an
argument to check to see if a specific video orientation is supported
(although it is true that the original property wasn’t named great
either):
supportsVideoOrientation -> isVideoOrientationSupported

Another case of

Like I said, I’d be willing to be talked into this, but at this point
I’m just really curious what the justification is. For simple cases
this seems to work well, but I’m really not enthused for what this
does to more complex or domain specific property names. I’m willing to
call this “unease after doing Obj-C too long”, but I’d like to
understand why the Swift team feels this is better.

The rationale is that it clarifies things that would otherwise be unclear.

HTH,

···

on Sun Jan 31 2016, Colin Cornaby <swift-evolution@swift.org> wrote:

--
-Dave

I'd like to add my voice to the many that are in favor of this proposal.

I agree with the general spirit of the guidelines and I think they
cover the most important points. They can always be expanded in the
future if experience deems it necessary but I'd rather have people
actually read and use the document than be put off by length and
complexity.

Various minor points

* Will these guidelines become part of "The Swift Programming
Language"? Personally I would support that.

Interesting idea. I think we may need the ability to update them on a
different schedule form the book. Perhaps the book should point at
them, though(?)

* I'm in favor of lowerCaseEnumCases

* var htmlElement = HTMLElement

* I don't think stripping the "Type" suffix from protocols is a clear
win, mostly a change of tradeoffs (which have already been discussed
extensively).
Ultimately I would be fine with either approach.

* One small idea I'd like to throw out there is whether the guidelines
should contain a small note that one might look to the standard
library for inspiration as well. It will have many examples for
following the guidelines as presented and might offer some helpful
precedent in cases where one is still unsure. In a way this is
probably obvious but it might not hurt to mention?

Well, maybe. If you mention all the things that wouldn't hurt to
mention... it ends up hurting :-) Trying to “omit needless words,”
here. :-)

* On the guidelines page the bullet point "When the first argument is
defaulted, it should have a distinct argument label." is wrapped in a
link (without a target). This is probably unintentional.

Actually, there's no link! This looks like a .css error, thanks. I've
alerted the CSS-master.

And a bit of rambling regarding the property vs method discussion:
The current situation seems to be that there are a lot of conflicting
"rules" (most with exceptions attached) that need to be weighed
against each other, with the decision coming down to "collective gut
feeling".

Unfortunately, I agree with that assessment.

It don't see a way to formalize them without breaking at least some
existing conventions and probably some heated discussions ;-). I also
wonder if that would actually produce better APIs on the whole or
simply produce clear rules for the sake of having clear rules with
APIs suffering in some cases...

Aside from the issues I've mentioned before of non-uniformity and wasted
cycles bikeshedding trivial choices, there's another problem with not
saying anything in this *particular* case...

Despite the Cocoa guidelines never explicitly stating that anything
*must* be a property, there is apparently an unwritten but very strong
rule among Cocoa developers that "unless the guidelines say it can't be
a property, it must be a property." People coming from that perspective
have looked at individual methods (in the standard library for example)
and insisted with great conviction that they ought to be properties.
However, if you ask them to look at the whole body of APIs, they come to
different conclusions (e.g. that APIs producing transformed
representations of collections, such as "x.reverse()," ought to be
methods, not properties). If nothing else, to preserve *my* sanity, I
need a guideline I can refer to. ;-) Even if it has some fuzzy edges,
that's better than nothing.

···

on Mon Feb 01 2016, Janosch Hildebrand <swift-evolution@swift.org> wrote:

--
-Dave

Just wanted to clarify the rule a bit. The strong rule in Cocoa APIs is that if a zero-arg method is idempotent it should be a property. In my opinion this has proven to be a rule that provides enough value at call sites, but is also a straightforward guideline to follow. I can see the perspective of APIs like `reversed` being a method and not a property, but then it really does muddy the waters for coming up with a simple to follow but useful rule. Tradeoffs… :-)

- Alex

···

On Feb 1, 2016, at 4:26 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Mon Feb 01 2016, Janosch Hildebrand <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I'd like to add my voice to the many that are in favor of this proposal.

I agree with the general spirit of the guidelines and I think they
cover the most important points. They can always be expanded in the
future if experience deems it necessary but I'd rather have people
actually read and use the document than be put off by length and
complexity.

Various minor points

* Will these guidelines become part of "The Swift Programming
Language"? Personally I would support that.

Interesting idea. I think we may need the ability to update them on a
different schedule form the book. Perhaps the book should point at
them, though(?)

* I'm in favor of lowerCaseEnumCases

* var htmlElement = HTMLElement

* I don't think stripping the "Type" suffix from protocols is a clear
win, mostly a change of tradeoffs (which have already been discussed
extensively).
Ultimately I would be fine with either approach.

* One small idea I'd like to throw out there is whether the guidelines
should contain a small note that one might look to the standard
library for inspiration as well. It will have many examples for
following the guidelines as presented and might offer some helpful
precedent in cases where one is still unsure. In a way this is
probably obvious but it might not hurt to mention?

Well, maybe. If you mention all the things that wouldn't hurt to
mention... it ends up hurting :-) Trying to “omit needless words,”
here. :-)

* On the guidelines page the bullet point "When the first argument is
defaulted, it should have a distinct argument label." is wrapped in a
link (without a target). This is probably unintentional.

Actually, there's no link! This looks like a .css error, thanks. I've
alerted the CSS-master.

And a bit of rambling regarding the property vs method discussion:
The current situation seems to be that there are a lot of conflicting
"rules" (most with exceptions attached) that need to be weighed
against each other, with the decision coming down to "collective gut
feeling".

Unfortunately, I agree with that assessment.

It don't see a way to formalize them without breaking at least some
existing conventions and probably some heated discussions ;-). I also
wonder if that would actually produce better APIs on the whole or
simply produce clear rules for the sake of having clear rules with
APIs suffering in some cases...

Aside from the issues I've mentioned before of non-uniformity and wasted
cycles bikeshedding trivial choices, there's another problem with not
saying anything in this *particular* case...

Despite the Cocoa guidelines never explicitly stating that anything
*must* be a property, there is apparently an unwritten but very strong
rule among Cocoa developers that "unless the guidelines say it can't be
a property, it must be a property." People coming from that perspective
have looked at individual methods (in the standard library for example)
and insisted with great conviction that they ought to be properties.
However, if you ask them to look at the whole body of APIs, they come to
different conclusions (e.g. that APIs producing transformed
representations of collections, such as "x.reverse()," ought to be
methods, not properties). If nothing else, to preserve *my* sanity, I
need a guideline I can refer to. ;-) Even if it has some fuzzy edges,
that's better than nothing.