When to use argument labels (a new approach)

This issue is going to surface any time a method with a preposition and a single defaulted argument. I would say:

copy(with: )

Although I think we might have problematic results no matter what guidelines we use for

func doSomethingWith(completionHandler: (()->Void)? = nil)

since this can be called as

doSomethingWith() // doSomething()

Or

doSomethingWith {...} // doSomething {...}

Here are the problems with putting the preposition inside the parentheses:

1. You can't "distribute" the preposition over a number of arguments:

       removeTracksHaving(mediaType: x, composer: y)

   you end up with

       removeTracks(havingMediaType: x, composer: y)

   if you try to fix this with conjunctions

       removeTracks(havingMediaType: x, andComposer: y, andLength: z)
                                        
   and the first argument has a default, you end up with the wrong
   implied semantics at the call site:

       removeTracks(andComposer: y)
       removeTracks(andLength: z)

2. You have to write:

       move(toX: horizontal, y: vertical)
   
Here are the problems with putting the preposition outside the
parentheses:

1. If all arguments have defaults and the method is called with zero
   arguments you have a dangling preposition as noted by Matthew. This
   only happens

2. You have to write:

       moveFrom(a, to: b)
   
IMO the consequences of putting prepositions inside the parens are worse
than the consequences of putting them outside.

···

on Sat Feb 06 2016, Matthew Judge <swift-evolution@swift.org> wrote:

On Feb 6, 2016, at 15:47, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

Le 6 févr. 2016 à 21:15, Douglas Gregor via swift-evolution <swift-evolution@swift.org> a écrit :

Sent from my iPhone

On Feb 6, 2016, at 9:21 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

So the preposition should move into the argument label if the argument is optional?

copy(withZone: zone = nil)

Zone is redundant with type information.

copy(with:)?
copy(withZone:)?

Wouldn’t it be possible to simply drop the copyWithZone: method that
is deprecated for some times now (To quote the doc: Zones are
ignored on iOS and 64-bit runtime on OS X. You should not use zones
in current development).

-Thorsten

Am 06.02.2016 um 14:45 schrieb Matthew Judge via swift-evolution <swift-evolution@swift.org>:

Very first method

copyWith(zone: Zone = nil)

can be called as

copyWith()

I'm assuming this is still something we don't want right?

On Feb 6, 2016, at 02:16, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

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

Given all the awesome feedback I've gotten on this thread, I went back
to the drawing board and came up with something new; I think this one
works. The previously-stated goals still apply:

[snip goals]

P.S. Doug is presently working on generating new importer results, based
   on these guidelines, for your perusal. They should be ready soon.

Here’s a link:

   Split first selector piece into base name/first argument label. by DougGregor · Pull Request #10 · apple/swift-3-api-guidelines-review · GitHub

Feedback welcome!

   - Doug

_______________________________________________
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

_______________________________________________
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

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

--
-Dave

One can consider everything inside the parentheses to be an argument list
and read them as "with/using an argument list". It works well if the
preceding part has a verb, such as

copy(zone: ...)
-> "Copy with [a single argument] zone equal to ..."

func doSomethingWith(completionHandler: (()->Void)? = nil)
-> "doSomething with a given completion handler or do something with a
default argument list."

Not sure if there's any value in spelling it out. I believe we use "with"
so it in Objective-C mostly out of necessity and can easily omit it in
Swift.

Ilya.

···

On Sat, Feb 6, 2016 at 10:12 PM, Matthew Judge via swift-evolution < swift-evolution@swift.org> wrote:

This issue is going to surface any time a method with a preposition and a
single defaulted argument. I would say:

copy(with: )

Although I think we might have problematic results no matter what
guidelines we use for

func doSomethingWith(completionHandler: (()->Void)? = nil)

since this can be called as

doSomethingWith() // doSomething()

Or

doSomethingWith {...} // doSomething {...}

> On Feb 6, 2016, at 15:47, Jean-Daniel Dupas via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
>> Le 6 févr. 2016 à 21:15, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> a écrit :
>>
>>
>>
>> Sent from my iPhone
>>
>>> On Feb 6, 2016, at 9:21 AM, Thorsten Seitz <tseitz42@icloud.com> > wrote:
>>>
>>> So the preposition should move into the argument label if the argument
is optional?
>>>
>>> copy(withZone: zone = nil)
>>
>> Zone is redundant with type information.
>>
>> copy(with:)?
>> copy(withZone:)?
>
> Wouldn’t it be possible to simply drop the copyWithZone: method that is
deprecated for some times now (To quote the doc: Zones are ignored on iOS
and 64-bit runtime on OS X. You should not use zones in current
development).
>
>>
>>> -Thorsten
>>>
>>>
>>>> Am 06.02.2016 um 14:45 schrieb Matthew Judge via swift-evolution < > swift-evolution@swift.org>:
>>>>
>>>> Very first method
>>>>
>>>> copyWith(zone: Zone = nil)
>>>>
>>>> can be called as
>>>>
>>>> copyWith()
>>>>
>>>> I'm assuming this is still something we don't want right?
>>>>
>>>>> On Feb 6, 2016, at 02:16, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
>>>>>
>>>>>
>>>>>> On Feb 5, 2016, at 1:32 PM, Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:
>>>>>>
>>>>>>
>>>>>> Given all the awesome feedback I've gotten on this thread, I went
back
>>>>>> to the drawing board and came up with something new; I think this
one
>>>>>> works. The previously-stated goals still apply:
>>>>>
>>>>>> [snip goals]
>>>>>
>>>>>> P.S. Doug is presently working on generating new importer results,
based
>>>>>> on these guidelines, for your perusal. They should be ready
soon.
>>>>>
>>>>> Here’s a link:
>>>>>
>>>>>
Split first selector piece into base name/first argument label. by DougGregor · Pull Request #10 · apple/swift-3-api-guidelines-review · GitHub
>>>>>
>>>>> Feedback welcome!
>>>>>
>>>>> - Doug
>>>>>
>>>>> _______________________________________________
>>>>> 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
>> _______________________________________________
>> 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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think part of where the current guidelines struggle is the ambiguity
of the term "argument label"

There's nothing ambiguous about it; it's the thing you write, with a
trailing colon, before an argument in an argument list.

so just for the sake of discussion I'm going to define terms to be
explicit (not saying these are precisely the right terms).

- External parameter names: names used to refer to parameters at the
use site

But they don't refer to parameters; they introduce arguments.

     moveFrom(x, to: y)

“to” introduces an argument. That's why we're calling them argument
labels.

a.moveTo(x: 1, y: 2) // external parameter names are "x" and "y"
a.addGestureRecognizer(b) // does not have an external parameter name

- Argument labels: words used to describe the argument being passed in
a.moveTo(x: 1, y: 2) // argument labels are "x" and "y"
a.addGestureRecognizer(b) // argument label is "GestureRecognizer"

Now you're redefining “argument label.” Why?

Both of these are referred to as "argument labels" in the guidelines

Not unless I made a big mistake. It is only supposed to mean what you
are calling an “external parameter name.”

and most of the discussion, but they are slightly different (though
overlapping) things. For instance, B.1 refers to "external parameter
names" and B.2 refers to "argument labels"

I think you've misread the language there. Would you mind re-evaluating
the rest of what you're saying here in that light? I think we need to
start from a common understanding.

···

on Sun Feb 07 2016, Matthew Judge <swift-evolution@swift.org> wrote:

I think my distinction between these terms makes the guidelines simpler with fewer caveats:

1. Prune needless and redundant words from the argument labels
(i.e. remove any word that can be removed without confusing the
semantic intent)
2. If the method reads as part of a grammatical phrase, prefer to
locate the first argument label as part of the base name instead of as
an external parameter name.
Special Cases/Exceptions:
a. Arguments with a default value should use an external parameter name
b. Arguments with similar semantic importance should be treated the
same (use external parameter names for argument labels or don't label
any)

Not saying these are right/perfect, but I do think the distinction of
guidelines for argument labels and external parameter will make the
rules simpler, clearer, and more consistent.

(Everything below here is applying these rules to each of the examples
used in Dave's original post.)

print(x) // Guideline 1 prunes argument label
a.contains(b) // Same
a.mergeWith(b) // Guideline 1 shortens argument label "WithCollection" to "With"
// Guideline 2 moves "With" into the base name

a.addGestureRecognizer(x)
// Guideline 1 does NOT prune "GestureRecognizer" because it would change the semantic meaning
// Guideline 2 moves it into the base name

- the following 3 examples from the original are treated the same under these rules, for the same reasons mentioned

    a.dismiss(b) // no, unless a is really dismissing b
    a.dismissAnimated(b) // no, not grammatical
    a.dismiss(animated: b) // yes, using a label

a.encodeWith(b) // Guideline 1 shortens argument label "WithCoder" to "With"
// Guideline 2 says put "With" to the base name

a.moveFrom(b, to: c) // Only change to the results of Dave's examples
// Guideline 1 shortens "fromScene" to "from" and "toScene" to "to"
// Exception (b) prevents Guideline 2 from moving "from" into the base name

* Note that I believe the only change to these guidelines required to
recover the behavior of Dave's original guidelines is modifying
Exception (b) to language similar to Dave's A.

- the following two examples would be covered by Exception (b) as well

    a.tracksWith(mediaType: b, composer: c)
    a.moveTo(x: 22, y: 99)

Sorry for the long email... Hopefully it's somewhat useful.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

Comments inline:

Looking over these guidelines again, I think I would be quite happy
with them given one very simple change to Rule 2:

If the first argument is part of a prepositional phrase WITH MULTIPLE
OBJECTS, put the parenthesis immediately after the preposition.

This eliminates the need for:

a.tracksHaving(mediaType: b)

which I think is inferior to:

a.tracksHavingMediaType(b)

Why do you think it's inferior?

1) One gripe is that it is much harder to reliably search for functions like this in code. You can do it in Xcode with Find>References, but if you are on a different platform, using different tools or looking at an online repository, you can’t do it without resorting to regular expressions. You need to find:

a.tracksHaving(mediaType: b)
and:
a.tracksHaving( mediaType: b ) // deliberate or accidental space
and:
a.tracksHaving(
    mediaType: a)
and:
a.tracksHaving( // a comment
    mediaType: a)

The regex search would have to match over line boundaries. Even in Xcode, it isn’t novice-friendly because Find>References is relatively hidden.

(This whole problem arises of course only when there could be other ‘tracksHaving()’ methods, like tracksHaving(composer:), etc. I expect that you would have to generally assume that would be the case for methods named this way).

To be fair, you *can* miss occurrences of a.tracksHavingMediaType(b) by using a simple text search with ‘.tracksHavingMediaType(‘ -- if there is a space before the parenthesis -- but I’m not sure that has ever happened to me. Putting a space before the paren in a function call is a much less common coding style than space after the paren.

2) It splits in the middle of a phrase, the least intuitive place to do so. It strikes at least some of us as quirky. As you say, this (along with the other changes) makes some Cocoa programmers, your main constituents, “wildly uncomfortable”, and it has the same effect on me, coming from a mostly C++ background (though I have found the Cocoa naming conventions to be pleasant to use over the years when writing Obj-C).

3) This way of treating prepositions and their objects is not consistent with the way verbs and their objects are treated:

a.tracksHaving(mediaType: b)
a.addSubView(b)

Or have I not been keeping up? Is there the intention of using: a.add(subView: b)? (It would really be a nightmare to search a code base for one particular version of an ‘add()’ method, out of what could be dozens of different ‘add()’s.

Assuming they are going to be treated differently, it won’t be immediately obvious to anyone why this is without reading not just the guidelines, but the rationale for the guidelines. How many programmers won’t even recall what a prepositional phrase is?

4) For me, it reduces readability and “immediate understandability” (admittedly subjective). It replaces a nice camelCase word boundary and intact phrase with a parenthesis in the middle of the phrase followed by a lowerCamelCase word. It doesn’t flow as nicely, possibly because there isn’t any common precedent in other programming languages for slicing things up this way.

—CK

···

On Feb 9, 2016, at 6:42 AM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Tue Feb 09 2016, Charles Kissinger <swift-evolution@swift.org> wrote:

On Feb 7, 2016, at 9:54 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Sun Feb 07 2016, Charles Kissinger <swift-evolution@swift.org> wrote:

The downside with the latter is that it doesn't scale up. When you want
to add a second criterion, you can't just add a defaulted parameter; you
have to change the signature (breaking code) or add one or more
overloads (creating cognitive weight for users).

Is this really an overriding concern though? I personally would not
choose to optimize for the occasional case of adding a defaulted
parameter at the cost of a general naming/labeling convention that we
both have expressed some discomfort with.

It's not an *overriding* concern; it's one of many. BTW, I don't
consider “some discomfort” on anyone's part to be an overriding concern
either. Most of these changes make Cocoa traditionalists wildly
uncomfortable. While I have compassion for that, the key thing is
understandability of Swift code into the future.

It's a (relatively speaking) minor issue, but IMO not glomming all that
description into the base name also results in code that's easier to
format in a balanced way, simply because there's a natural place to
break the line after the parenthesis.

I view this in a quite different way. Breaking a line after
'a.tracksHaving(‘ leaves the reader in quite a bit of suspense!

Suspense is good in these cases; it means the reader isn't going to stop
at the end of the line. One should feel relief only when one has taken
in all the important parts of the call.

It might be easier to format, but overall readability would suffer.

I don't see how

a.long.line.ending.with.tracksHavingMediaType(
   mp3)

is any more readable than

a.long.line.ending.with.tracksHaving(
   mediaType: mp3)

to me, it's less readable.

On the other hand, functions like:

a.tracksWith(mediaType: b, composer: c)
a.moveTo(x: 22, y: 99)

would remain as is, because there are multiple objects for the preposition.

This also neatly solves the ‘moveFrom(a to: b)’ problem. There are two
separate prepositional phrases involved, 'from a' and 'to b', each
with a single object, so:

move(from: a to: b)

is, I believe, fully compatible with the guidelines.

I don't see anything in the guidelines I've proposed, even with your
modification, that would cause "from" to be placed inside the
parentheses. The way I read it this case still falls right into B1,
resulting in "moveFrom(a, to: b)”

I must be interpreting B.1 differently than you intended. It appears
to me to be discussing the cases where first arguments *can* be
unlabeled. You seem to be implying here that it says that the first
argument *must* be unlabeled when it forms a part of a grammatical
phrase, otherwise move(from: a, to: b) would be fine. As I read the
guidelines, though, only B.2 (which I would modify) requires
moveFrom(a, to: b), because of the preposition. What am I not getting
here?

Maybe I was mistaken. I'm working on new wording that allows "from" to
move inside the parens under the same guideline that results in argument
labels for all arguments when the method is a factory function. I'll
let you know when that's ready.

—CK

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

Given all the awesome feedback I've gotten on this thread, I went back
to the drawing board and came up with something new; I think this one
works. The previously-stated goals still apply:

* describe when and where to use argument labels
* require labels in many of the cases people have asked for them
* are understandable by humans (this means relatively simple)
* preserve important semantics communicated by existing APIs.

Please keep in mind that it is a non-goal to capture considerations we
think have a bearing on good names (such as relatedness of parameters):
it's to create simple guidelines that have the right effect in nearly
all cases.

A. When arguments can't be usefully distinguished from one another, none
should have argument labels, e.g. min(x,y), zip(x,y,z).

B. Otherwise,

1. At the call site, a first parameter that has no argument label must
  form part of a grammatical phrase that starts with the basename, less
  any trailing nouns.

    print(x)
    a.contains(b)
    a.mergeWith(b)
    a.addGestureRecognizer(x)
         ^~~~~~~~~~~~~~~~~ trailing noun

  This phrase must have the correct semantic implications, so, e.g.

    a.dismiss(b) // no, unless a is really dismissing b
    a.dismissAnimated(b) // no, not grammatical
    a.dismiss(animated: b) // yes, using a label

2. If the first argument is part of a prepositional phrase, put the
  parenthesis immediately after the preposition.

    a.encodeWith(b)
    a.moveFrom(b, to: c)

  Thus, if words are required for any reason between the preposition
  and the first argument, they go into the first argument label.

    a.tracksWith(mediaType: b, composer: c)
    a.moveTo(x: 22, y: 99)

Notes:

a. I would recommend prepositions other than "with" in nearly all
cases, but that's not the point of these rules.
b. I can understand the aesthetic appeal of

a.move(from: b, to: c)

but I believe it is not a clear enough improvement to justify
additional complexity in the guidelines.

Questions:

1. I'm not expecting these guidelines to make everybody optimally happy,
all the time, but they shouldn't be harmful. Are there any cases for
which they produce results you couldn't live with?

2. Are there any cases where you'd be confused about how to apply these
guidelines?

Thanks in advance for all your valuable input!

P.S. Doug is presently working on generating new importer results, based
  on these guidelines, for your perusal. They should be ready soon.

--
-Dave

_______________________________________________
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

_______________________________________________
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

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

  func attachmentForImage(image: UIImage) throws -> Attachment {
  func attachmentForData(data: NSData) -> Attachment {
  func attachmentForFileURL(url: NSURL) throws -> Attachment {

This should be `attachmentFor(image:)`, `attachmentFor(data:)`, and `attachmentFor(fileURL:)`. This seems like a win, since related methods for different data types are grouped more tightly together. (I could also — like you suggested about not optimizing for method families — make an enum, but it would be overkill since it’s not API for public consumption. I should mark those as private.)

If such convention were to be adopted, we could throw away our favorite grep tools.

Functions with many parameters are often more legible when their invocation is split across several lines. And generally speaking, a developer can liberally call a function on a single line, or on several lines:

  attachmentFor(image: …, extraParam: …)
  attachmentFor(
      image: …,
      extraParam: …)

OK so now if I want to look for all invocations of attachmentFor(image:extraParam:) in my code, I have to look for "attachmentFor", and get all the unrelated results attachmentFor(data:…), attachmentFor(fileURL:…), etc.

Whereas if the function were named attachmentForImage(_:extraParam:), I could look for "attachmentForImage", and get much more precise search results.

So… I’m happy people discuss how nice `attachmentFor(image:)` looks, and my opinion on how nice or ugly it looks is not my point. My point is that I want my tools to help me doing my job.

I admit that it’s hard to leave coding habits, and I have slightly over-reacted above.

I can’t wait for Xcode to bring better Swift code navigation tools, that would make lower the usefulness of text searching.

Gwendal

Right. I’m not compelled by this argument, because it’s a tooling problem. I don’t believe language design lives in vacuum, outside of what the tools allow. Notice how the guidelines argue for the removal of type information repeated in the name — the information is already there and in situations when the context isn’t enough, it’s easy to view this information.

Besides — this seems like an edge case anyway. I very rarely see invocations long enough to be compelled to split it into multiple lines, and even if I would, I’d do it like this:

  attachmentFor(image: …,
        extraParam: ….)

And you can always search for /attachmentFor\(\s*image:/m in the (imho very rare) circumstance when you have a method family like that AND you want to search for just one of them AND there’s so many you can’t just look through the search results for `attachmentFor` AND you follow a convention where the first parameter label wouldn’t be in the same line as the method name.

— Radek

but I want to make sure if I interpret the proposed guidelines right.

  func actionForCommand(command: UIKeyCommand) -> String? {

This should become “actionFor(command: c)” — which isn’t an obvious

That looks like a call, in which case the API above doesn't allow an
argument label.

I’m sorry — I got confused — what do you mean here?

Sorry, I didn't notice that you both transitioned from declaring
(actionForCommand(_)) to calling (actionFor(command:)) *and* changed the
API at the same time.

So, I would say the guidelines say the call should look like:

   b.action(for: c)

It should be `createAttribute(tag: t, data: d)`.

Again that looks like a call, so for the above declaration it would be

    createAttribute(t, d)

Alternatively, it could be `attributeFor(tag: t, data: d)` — I could
go either way.

Why “for?” Can you explain the semantics of this method (or show a BCDC)?

This is a initializer-like helper method that instantiates a
SecKeychainAttribute from passed parameters.

If it's a factory, I think guidelines prescribe the call should look like:

  makeAttribute(tag: t, data: d)

So that’s interesting, because there’s a difference in convention
between a factory/initializer-like function:

  makeFoo(this:, that:)

and a getter/finder-like function:

  foo(withThis:, that:)

Yes, that's the intention. When the distinction makes no difference,
you should treat the function like a getter/finder, IIUC.

···

on Sat Feb 13 2016, Radosław Pietruszewski <swift-evolution@swift.org> wrote:

I think that (in particular the difference in the treatment of
argument labels) is the part that makes me most uncomfortable about
the latest draft. Perhaps it isn’t such a big deal, since you usually
don’t see the two next to each other, and as was noted, most
finder-like functions only come with a single parameter, while
initializers and factory methods very commonly have many parameters...

--
-Dave

As the conversation has moved on really far now I only have a couple minor things here.

I do find some of the rules worded in ways that are hard to apply in
the presence of trailing nouns; I’m not sure the guidelines are strong
enough here to force the “right” outcome.

Consider this example:

// not-intended:
a.tracksWithMediaCharacteristic(b, composer: c)

…applying our guidelines:

- `tracks with media characteristic b` is a grammatical phrase

I went through a series of thoughts on this:

1. I'm not sure it is grammatical (I'll have to consult with a
linguist).

2. I understand why it sounds natural: this is the somewhat misleading
result of using a single-character identifier in the example. It's like
talking about a hypothetical "person A" and "person B". You wouldn't think
"Person Joe" was grammatical.

3. Yeah, but "umbrellas with color yellow" is perfectly fine, if
slightly unnatural, and it has the same grammatical structure. My
wife points out that it's like something you would say in poetry to
make rhyme or meter work.

4. Again I need to consult with a linguist, but I now have hope that it
actually is grammatical, meaning the whole “skipping trailing nouns
on the base name” wrinkle can be eliminated from the guidelines.
Thanks!

It’s a good example of “grammaticality vs acceptability” issues; for
another other example, “The Color Purple”. Even “Person Joe” is ok in
the right context, but as it’s unusual and tricky to parse it
seemingly requires a pause (or a comma when written), e.g. consider
“The person, Joe, bit the dog, Fido”.

Yep; great points.

For the above example, I think there’s a strong sense that the
phrasing is unusual, and the lack of articles isn’t helping; I’d order
the acceptability like this:

tracks with the “legible” media-characteristic // <- most-natural/least-unusual
tracks with the media-characteristic “legible”
tracks with media-characteristic “legible”
tracks with “legible” media-characteristic // <- worst due to interpretational ambiguity

Well, and the lack of quotation marks in the name doesn't help either.
But when you s/legible/X/ I'd say the third one is perfectly natural and
the other ones are all a bit strange.

Contrast with "users with the ‘suspended' account-status” vs “users with the suspended account-status” vs “users with suspended account-status” vs “users with account-status suspended”.

…and I think the the perceived acceptability improves
substantially—and seemingly uniformly—with some more context:

let t = (all of a's) tracks with the “legible” media-characteristic
let t = (all of a's) tracks with the media-characteristic “legible”
let t = (all of a's) tracks with media-characteristic “legible”
let t = (all of a's) tracks with “legible” media-characteristic // <- still the worst, for the same reason

…which sort of situation was why I thought it was risky to put too
much weight on grammatical rules in the guidelines: I suspect that a
lot of what needs to be “ungrammatical” for the guidelines will in
practice be closer to “questionable”,

Can you explain what you mean by "needs to be “ungrammatical” for the
guidelines?”

In hindsight that is rather terse!

My assumption is the guidelines are meant to steer users to make some decisions and not others, and my other assumption is that “is this grammatical (Y/N)” isn’t actually strong enough to do that steering (many more short sequences of words are technically grammatical than one might wish).

But, there’s not a better phrasing than “forms a grammatical phrase”, either; you can’t realistically write “forms a grammatical phrase (that also isn’t weird, hard to parse, or otherwise unusual)”, even if that’s closer to the spirit of the steered-toward decisions.

That was what I meant; the discussion’s moved on enough not much point continuing this specific point any further.

and it can be difficult to keep one’s sense of the “questionable”
calibrated; this is especially true if you spend a lot of time exposed
to “odd" language, e.g. English-like source code.

Heh, indeed. That's why I think it's better to have a solid criterion
like “is it grammatical?” than to use something like “is it questionable?”

Given the perceived oddness of the trailing-noun usage, the best
rule-adjustment might be “is it a complete phrase? If there’s a
trailing noun, you may *either* ignore the trailing noun *or* ignore
the argument—but not both—when making that decision,” except pithier.

I wonder if “use single-letter identifiers to evaluate grammaticality at
a hypothetical use-site” is an approach that would work without any
“ignoring?”

I think it might, worth a try at least.

···

On Feb 7, 2016, at 11:37 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Sun Feb 07 2016, plx <swift-evolution@swift.org> wrote:

On Feb 6, 2016, at 11:31 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org> wrote:
on Sat Feb 06 2016, plx <swift-evolution@swift.org> wrote:

I think we might also want to consider it legitimate to evaluate calls
taking enum parameters using actual enum case names, as they can account
for a lot of words and can be controlled to make calls read
grammatically.

--
-Dave

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

This thread looks seems like it would be best addressed by having everyone write up ideal examples of a bunch of lines of code, with explanations, which evolve and get edited as our thoughts evolve. Has this been started? This is important to address, but it’s code, and so can’t be reasonably assessed in mail.

Let me be clear: these API guidelines are *not* going to optimize for
churning out APIs without careful consideration; it's thoroughly
incompatible with their mission. If you want that freedom, you're free
to ignore the guidelines. Sorry to be blunt, but that's how it is.

Long day? :) No worries.

So the preposition should move into the argument label if the argument is optional?

copy(withZone: zone = nil)

That's a good idea.

It seems unfortunate that the placement of the preposition should
change depending on whether there is a default argument or not,
especially since it is reasonable to imagine that an API evolves to
gain a default argument later on.

You're right; it would complicate the rules significantly, too.

···

on Sat Feb 06 2016, Douglas Gregor <swift-evolution@swift.org> wrote:

On Feb 6, 2016, at 10:08 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Sat Feb 06 2016, Thorsten Seitz <swift-evolution@swift.org> wrote:

  - Doug

-Thorsten

Am 06.02.2016 um 14:45 schrieb Matthew Judge via swift-evolution >>>> <swift-evolution@swift.org>:

Very first method

copyWith(zone: Zone = nil)

can be called as

copyWith()

I'm assuming this is still something we don't want right?

On Feb 6, 2016, at 02:16, Douglas Gregor via swift-evolution >>>>> <swift-evolution@swift.org> wrote:

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

Given all the awesome feedback I've gotten on this thread, I went back
to the drawing board and came up with something new; I think this one
works. The previously-stated goals still apply:

[snip goals]

P.S. Doug is presently working on generating new importer results, based
   on these guidelines, for your perusal. They should be ready soon.

Here’s a link:

  Split first selector piece into base name/first argument label. by DougGregor · Pull Request #10 · apple/swift-3-api-guidelines-review · GitHub

Feedback welcome!

  - Doug

_______________________________________________
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

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

--
-Dave

_______________________________________________
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

   if you try to fix this with conjunctions
       removeTracks(havingMediaType: x, andComposer: y, andLength: z)

I'm confused about this.
Is it necessary to use "and" because Apple needs to automate the conversion
of Cocoa libraries? Otherwise, wouldn't using "having" for all three makes
this a non-issue?

    removeTracks( havingMediaType: x, havingComposer: y, havingLength: z )

Sorry, the second example was supposed to be

func doSomething(completionHandler completion: (()->Void)? = nil)

···

On Sun, Feb 7, 2016 at 7:51 PM, ilya <ilya.nikokoshev@gmail.com> wrote:

One can consider everything inside the parentheses to be an argument list
and read them as "with/using an argument list". It works well if the
preceding part has a verb, such as

copy(zone: ...)
-> "Copy with [a single argument] zone equal to ..."

func doSomethingWith(completionHandler: (()->Void)? = nil)
-> "doSomething with a given completion handler or do something with a
default argument list."

Not sure if there's any value in spelling it out. I believe we use "with"
so it in Objective-C mostly out of necessity and can easily omit it in
Swift.

Ilya.

On Sat, Feb 6, 2016 at 10:12 PM, Matthew Judge via swift-evolution < > swift-evolution@swift.org> wrote:

This issue is going to surface any time a method with a preposition and a
single defaulted argument. I would say:

copy(with: )

Although I think we might have problematic results no matter what
guidelines we use for

func doSomethingWith(completionHandler: (()->Void)? = nil)

since this can be called as

doSomethingWith() // doSomething()

Or

doSomethingWith {...} // doSomething {...}

> On Feb 6, 2016, at 15:47, Jean-Daniel Dupas via swift-evolution < >> swift-evolution@swift.org> wrote:
>
>
>> Le 6 févr. 2016 à 21:15, Douglas Gregor via swift-evolution < >> swift-evolution@swift.org> a écrit :
>>
>>
>>
>> Sent from my iPhone
>>
>>> On Feb 6, 2016, at 9:21 AM, Thorsten Seitz <tseitz42@icloud.com> >> wrote:
>>>
>>> So the preposition should move into the argument label if the
argument is optional?
>>>
>>> copy(withZone: zone = nil)
>>
>> Zone is redundant with type information.
>>
>> copy(with:)?
>> copy(withZone:)?
>
> Wouldn’t it be possible to simply drop the copyWithZone: method that is
deprecated for some times now (To quote the doc: Zones are ignored on iOS
and 64-bit runtime on OS X. You should not use zones in current
development).
>
>>
>>> -Thorsten
>>>
>>>
>>>> Am 06.02.2016 um 14:45 schrieb Matthew Judge via swift-evolution < >> swift-evolution@swift.org>:
>>>>
>>>> Very first method
>>>>
>>>> copyWith(zone: Zone = nil)
>>>>
>>>> can be called as
>>>>
>>>> copyWith()
>>>>
>>>> I'm assuming this is still something we don't want right?
>>>>
>>>>> On Feb 6, 2016, at 02:16, Douglas Gregor via swift-evolution < >> swift-evolution@swift.org> wrote:
>>>>>
>>>>>
>>>>>> On Feb 5, 2016, at 1:32 PM, Dave Abrahams via swift-evolution < >> swift-evolution@swift.org> wrote:
>>>>>>
>>>>>>
>>>>>> Given all the awesome feedback I've gotten on this thread, I went
back
>>>>>> to the drawing board and came up with something new; I think this
one
>>>>>> works. The previously-stated goals still apply:
>>>>>
>>>>>> [snip goals]
>>>>>
>>>>>> P.S. Doug is presently working on generating new importer results,
based
>>>>>> on these guidelines, for your perusal. They should be ready
soon.
>>>>>
>>>>> Here’s a link:
>>>>>
>>>>>
Split first selector piece into base name/first argument label. by DougGregor · Pull Request #10 · apple/swift-3-api-guidelines-review · GitHub
>>>>>
>>>>> Feedback welcome!
>>>>>
>>>>> - Doug
>>>>>
>>>>> _______________________________________________
>>>>> 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
>> _______________________________________________
>> 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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

There are a great number of vacuous uses of "with" in Objective-C API
names, but some of them are meaningful... which makes the importer's
job quite tricky.

···

on Sun Feb 07 2016, ilya <swift-evolution@swift.org> wrote:

One can consider everything inside the parentheses to be an argument list
and read them as "with/using an argument list". It works well if the
preceding part has a verb, such as

copy(zone: ...)
-> "Copy with [a single argument] zone equal to ..."

func doSomethingWith(completionHandler: (()->Void)? = nil)
-> "doSomething with a given completion handler or do something with a
default argument list."

Not sure if there's any value in spelling it out. I believe we use "with"
so it in Objective-C mostly out of necessity and can easily omit it in
Swift.

--
-Dave

> I think part of where the current guidelines struggle is the ambiguity
> of the term "argument label"

There's nothing ambiguous about it; it's the thing you write, with a
trailing colon, before an argument in an argument list.

> so just for the sake of discussion I'm going to define terms to be
> explicit (not saying these are precisely the right terms).
>
> - External parameter names: names used to refer to parameters at the
> use site

But they don't refer to parameters; they introduce arguments.

     moveFrom(x, to: y)

“to” introduces an argument. That's why we're calling them argument
labels.

Agreed - I was just trying to distinguish between the two concepts.

> a.moveTo(x: 1, y: 2) // external parameter names are "x" and "y"
> a.addGestureRecognizer(b) // does not have an external parameter name
>
> - Argument labels: words used to describe the argument being passed in
> a.moveTo(x: 1, y: 2) // argument labels are "x" and "y"
> a.addGestureRecognizer(b) // argument label is "GestureRecognizer"

Now you're redefining “argument label.” Why?

I don't so much want to redefine "argument label" as have a term to
describe this concept.

> Both of these are referred to as "argument labels" in the guidelines

Not unless I made a big mistake. It is only supposed to mean what you
are calling an “external parameter name.”

I was reading this part of B.2: "first argument is part of a prepositional
phrase, put the parenthesis immediately after the preposition." as "move
the preposition from the first argument label into the base name" but
you're right, your language doesn't actually imply that the preposition is
part of the argument label. My apologies.

> and most of the discussion, but they are slightly different (though
> overlapping) things. For instance, B.1 refers to "external parameter
> names" and B.2 refers to "argument labels"

I think you've misread the language there. Would you mind re-evaluating
the rest of what you're saying here in that light? I think we need to
start from a common understanding.

The key point from the rest of what I'm saying is that the guideline for
when to omit words in a method/function name can be more consistently and
clearly applied to my redefinition of "argument label"... The reason we
keep "gestureRecognizer" is the same regardless of whether it is spelled:
a.add(gestureRecognizer: b)
a.addGestureRecognizer(b)
and the reason we omit the argument label (original definition) in the
following are different.
anArray.add(b) // Prune "Element" w/o changing semantic meaning
a.addGestureRecognizer(b) // Words describing the first argument are
already in the base name

···

On Mon, Feb 8, 2016 at 12:45 AM, Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

on Sun Feb 07 2016, Matthew Judge <swift-evolution@swift.org> wrote:

> I think my distinction between these terms makes the guidelines simpler
with fewer caveats:
>
> 1. Prune needless and redundant words from the argument labels
> (i.e. remove any word that can be removed without confusing the
> semantic intent)
> 2. If the method reads as part of a grammatical phrase, prefer to
> locate the first argument label as part of the base name instead of as
> an external parameter name.
> Special Cases/Exceptions:
> a. Arguments with a default value should use an external parameter name
> b. Arguments with similar semantic importance should be treated the
> same (use external parameter names for argument labels or don't label
> any)
>
> Not saying these are right/perfect, but I do think the distinction of
> guidelines for argument labels and external parameter will make the
> rules simpler, clearer, and more consistent.
>
> (Everything below here is applying these rules to each of the examples
> used in Dave's original post.)
>
> print(x) // Guideline 1 prunes argument label
> a.contains(b) // Same
> a.mergeWith(b) // Guideline 1 shortens argument label "WithCollection"
to "With"
> // Guideline 2 moves "With" into the base name
>
> a.addGestureRecognizer(x)
> // Guideline 1 does NOT prune "GestureRecognizer" because it would
change the semantic meaning
> // Guideline 2 moves it into the base name
>
> - the following 3 examples from the original are treated the same under
these rules, for the same reasons mentioned
>>>>> a.dismiss(b) // no, unless a is really dismissing b
>>>>> a.dismissAnimated(b) // no, not grammatical
>>>>> a.dismiss(animated: b) // yes, using a label
>
> a.encodeWith(b) // Guideline 1 shortens argument label "WithCoder" to
"With"
> // Guideline 2 says put "With" to the base name
>
> a.moveFrom(b, to: c) // Only change to the results of Dave's examples
> // Guideline 1 shortens "fromScene" to "from" and "toScene" to "to"
> // Exception (b) prevents Guideline 2 from moving "from" into the base
name
>
> * Note that I believe the only change to these guidelines required to
> recover the behavior of Dave's original guidelines is modifying
> Exception (b) to language similar to Dave's A.
>
> - the following two examples would be covered by Exception (b) as well
>>>>> a.tracksWith(mediaType: b, composer: c)
>>>>> a.moveTo(x: 22, y: 99)
>
> Sorry for the long email... Hopefully it's somewhat useful.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

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

Comments inline:

Looking over these guidelines again, I think I would be quite happy
with them given one very simple change to Rule 2:

If the first argument is part of a prepositional phrase WITH MULTIPLE
OBJECTS, put the parenthesis immediately after the preposition.

This eliminates the need for:

a.tracksHaving(mediaType: b)

which I think is inferior to:

a.tracksHavingMediaType(b)

Why do you think it's inferior?

1) One gripe is that it is much harder to reliably search for
functions like this in code. You can do it in Xcode with
>References, but if you are on a different platform, using
different tools or looking at an online repository, you can’t do it
without resorting to regular expressions. You need to find:

a.tracksHaving(mediaType: b)
and:
a.tracksHaving( mediaType: b ) // deliberate or accidental space
and:
a.tracksHaving(
    mediaType: a)
and:
a.tracksHaving( // a comment
    mediaType: a)

The regex search would have to match over line boundaries. Even in
Xcode, it isn’t novice-friendly because Find>References is relatively
hidden.

A fair point.

(This whole problem arises of course only when there could be other
‘tracksHaving()’ methods, like tracksHaving(composer:), etc. I expect
that you would have to generally assume that would be the case for
methods named this way).

To be fair, you *can* miss occurrences of a.tracksHavingMediaType(b)
by using a simple text search with ‘.tracksHavingMediaType(‘ -- if
there is a space before the parenthesis -- but I’m not sure that has
ever happened to me. Putting a space before the paren in a function
call is a much less common coding style than space after the paren.

You will also fail to find methods with different later argument labels,
no matter which convention we choose here. Searchability is a nice
feature, and I agree that it suffers somewhat when long base names are
split up.

2) It splits in the middle of a phrase, the least intuitive place to
do so. It strikes at least some of us as quirky. As you say, this
(along with the other changes) makes some Cocoa programmers, your main
constituents, “wildly uncomfortable”, and it has the same effect on
me, coming from a mostly C++ background (though I have found the Cocoa
naming conventions to be pleasant to use over the years when writing
Obj-C).

FWIW, the latest direction
<http://article.gmane.org/gmane.comp.lang.swift.evolution/6342&gt; avoids
that by moving prepositions inside the parentheses.

3) This way of treating prepositions and their objects is not
consistent with the way verbs and their objects are treated:

a.tracksHaving(mediaType: b)
a.addSubView(b)

Under the latest:

  a.tracks(havingMediaType: b)
  a.addSubView(b)

That's still inconsistent if your expectation is that these two calls have the
same “shape.”

There's significant consensus that the role of the thing being added is
a fundamental-enough part of the semantics that it should be visible in
the base name.

Or have I not been keeping up? Is there the intention of using:
a.add(subView: b)?

No such intention exists, to date.

(It would really be a nightmare to search a code base for one
particular version of an ‘add()’ method, out of what could be dozens
of different ‘add()’s.

Assuming they are going to be treated differently, it won’t be
immediately obvious to anyone why this is without reading not just the
guidelines, but the rationale for the guidelines. How many programmers
won’t even recall what a prepositional phrase is?

Hopefully, copious examples and links to definitions of grammatical
terms (as I have used throughout the existing guidelines document) will
be enough to guide people in the right direction.

4) For me, it reduces readability and “immediate understandability”
(admittedly subjective). It replaces a nice camelCase word boundary
and intact phrase with a parenthesis in the middle of the phrase
followed by a lowerCamelCase word. It doesn’t flow as nicely, possibly
because there isn’t any common precedent in other programming
languages for slicing things up this way.

Understood. I think all of us agree about the oddness of splitting up
the phrase. How does the latest idea (linked above) look to you?

···

on Tue Feb 09 2016, Charles Kissinger <swift-evolution@swift.org> wrote:

On Feb 9, 2016, at 6:42 AM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Tue Feb 09 2016, Charles Kissinger <swift-evolution@swift.org> wrote:

On Feb 7, 2016, at 9:54 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Sun Feb 07 2016, Charles Kissinger <swift-evolution@swift.org> wrote:

—CK

The downside with the latter is that it doesn't scale up. When you want
to add a second criterion, you can't just add a defaulted parameter; you
have to change the signature (breaking code) or add one or more
overloads (creating cognitive weight for users).

Is this really an overriding concern though? I personally would not
choose to optimize for the occasional case of adding a defaulted
parameter at the cost of a general naming/labeling convention that we
both have expressed some discomfort with.

It's not an *overriding* concern; it's one of many. BTW, I don't
consider “some discomfort” on anyone's part to be an overriding concern
either. Most of these changes make Cocoa traditionalists wildly
uncomfortable. While I have compassion for that, the key thing is
understandability of Swift code into the future.

It's a (relatively speaking) minor issue, but IMO not glomming all that
description into the base name also results in code that's easier to
format in a balanced way, simply because there's a natural place to
break the line after the parenthesis.

I view this in a quite different way. Breaking a line after
'a.tracksHaving(‘ leaves the reader in quite a bit of suspense!

Suspense is good in these cases; it means the reader isn't going to stop
at the end of the line. One should feel relief only when one has taken
in all the important parts of the call.

It might be easier to format, but overall readability would suffer.

I don't see how

a.long.line.ending.with.tracksHavingMediaType(
   mp3)

is any more readable than

a.long.line.ending.with.tracksHaving(
   mediaType: mp3)

to me, it's less readable.

On the other hand, functions like:

a.tracksWith(mediaType: b, composer: c)
a.moveTo(x: 22, y: 99)

would remain as is, because there are multiple objects for the preposition.

This also neatly solves the ‘moveFrom(a to: b)’ problem. There are two
separate prepositional phrases involved, 'from a' and 'to b', each
with a single object, so:

move(from: a to: b)

is, I believe, fully compatible with the guidelines.

I don't see anything in the guidelines I've proposed, even with your
modification, that would cause "from" to be placed inside the
parentheses. The way I read it this case still falls right into B1,
resulting in "moveFrom(a, to: b)”

I must be interpreting B.1 differently than you intended. It appears
to me to be discussing the cases where first arguments *can* be
unlabeled. You seem to be implying here that it says that the first
argument *must* be unlabeled when it forms a part of a grammatical
phrase, otherwise move(from: a, to: b) would be fine. As I read the
guidelines, though, only B.2 (which I would modify) requires
moveFrom(a, to: b), because of the preposition. What am I not getting
here?

Maybe I was mistaken. I'm working on new wording that allows "from" to
move inside the parens under the same guideline that results in argument
labels for all arguments when the method is a factory function. I'll
let you know when that's ready.

—CK

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

Given all the awesome feedback I've gotten on this thread, I went back
to the drawing board and came up with something new; I think this one
works. The previously-stated goals still apply:

* describe when and where to use argument labels
* require labels in many of the cases people have asked for them
* are understandable by humans (this means relatively simple)
* preserve important semantics communicated by existing APIs.

Please keep in mind that it is a non-goal to capture considerations we
think have a bearing on good names (such as relatedness of parameters):
it's to create simple guidelines that have the right effect in nearly
all cases.

A. When arguments can't be usefully distinguished from one another, none
should have argument labels, e.g. min(x,y), zip(x,y,z).

B. Otherwise,

1. At the call site, a first parameter that has no argument label must
  form part of a grammatical phrase that starts with the basename, less
  any trailing nouns.

    print(x)
    a.contains(b)
    a.mergeWith(b)
    a.addGestureRecognizer(x)
         ^~~~~~~~~~~~~~~~~ trailing noun

  This phrase must have the correct semantic implications, so, e.g.

    a.dismiss(b) // no, unless a is really dismissing b
    a.dismissAnimated(b) // no, not grammatical
    a.dismiss(animated: b) // yes, using a label

2. If the first argument is part of a prepositional phrase, put the
  parenthesis immediately after the preposition.

    a.encodeWith(b)
    a.moveFrom(b, to: c)

  Thus, if words are required for any reason between the preposition
  and the first argument, they go into the first argument label.

    a.tracksWith(mediaType: b, composer: c)
    a.moveTo(x: 22, y: 99)

Notes:

a. I would recommend prepositions other than "with" in nearly all
cases, but that's not the point of these rules.
b. I can understand the aesthetic appeal of

a.move(from: b, to: c)

but I believe it is not a clear enough improvement to justify
additional complexity in the guidelines.

Questions:

1. I'm not expecting these guidelines to make everybody optimally happy,
all the time, but they shouldn't be harmful. Are there any cases for
which they produce results you couldn't live with?

2. Are there any cases where you'd be confused about how to apply these
guidelines?

Thanks in advance for all your valuable input!

P.S. Doug is presently working on generating new importer results, based
  on these guidelines, for your perusal. They should be ready soon.

--
-Dave

_______________________________________________
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

_______________________________________________
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

_______________________________________________
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

Besides — this seems like an edge case anyway. I very rarely see invocations long enough to be compelled to split it into multiple lines, and even if I would, I’d do it like this:

  attachmentFor(image: …,
        extraParam: ….)

Rule: invocation may use two parameters on the same line, unless that’s too long.
Hack: Use the same line for poorly-named methods names that look like they came form Objective-C.

function(argument1: 1, argument2: true)

function(
   argument1: 1,
   argument2: true,
   argument3: "Troo"
)

functionWithLongName(
   longArgumentLabel1: longArgumentName,
   longArgumentLabel2: longArgumentName
)

functionNamedWrongWithArgument1(1,
   argument2: true,
   argument3: "Troo"
)

  func attachmentForImage(image: UIImage) throws -> Attachment {
  func attachmentForData(data: NSData) -> Attachment {
  func attachmentForFileURL(url: NSURL) throws -> Attachment {

This should be `attachmentFor(image:)`, `attachmentFor(data:)`, and `attachmentFor(fileURL:)`. This seems like a win, since related methods for different data types are grouped more tightly together. (I could also — like you suggested about not optimizing for method families — make an enum, but it would be overkill since it’s not API for public consumption. I should mark those as private.)

If such convention were to be adopted, we could throw away our favorite grep tools.

Functions with many parameters are often more legible when their invocation is split across several lines. And generally speaking, a developer can liberally call a function on a single line, or on several lines:

  attachmentFor(image: …, extraParam: …)
  attachmentFor(
      image: …,
      extraParam: …)

OK so now if I want to look for all invocations of attachmentFor(image:extraParam:) in my code, I have to look for "attachmentFor", and get all the unrelated results attachmentFor(data:…), attachmentFor(fileURL:…), etc.

Whereas if the function were named attachmentForImage(_:extraParam:), I could look for "attachmentForImage", and get much more precise search results.

So… I’m happy people discuss how nice `attachmentFor(image:)` looks, and my opinion on how nice or ugly it looks is not my point. My point is that I want my tools to help me doing my job.

I admit that it’s hard to leave coding habits, and I have slightly over-reacted above.

I can’t wait for Xcode to bring better Swift code navigation tools, that would make lower the usefulness of text searching.

Gwendal

Right. I’m not compelled by this argument, because it’s a tooling problem.

I don’t believe language design lives in vacuum, outside of what the tools allow. Notice how the guidelines argue for the removal of type information repeated in the name — the information is already there and in situations when the context isn’t enough, it’s easy to view this information.

Sure. But when the tools are lagging, we end with a plain and simple regression. So I’ll follow you for the sole reason that Swift is still experimental, and that we don’t have to expect a environment that matches the one we used to have until Swift 3.x or Swift 4.

Besides — this seems like an edge case anyway. I very rarely see invocations long enough to be compelled to split it into multiple lines, and even if I would, I’d do it like this:

  attachmentFor(image: …,
        extraParam: ….)

And you can always search for /attachmentFor\(\s*image:/m in the (imho very rare) circumstance when you have a method family like that AND you want to search for just one of them AND there’s so many you can’t just look through the search results for `attachmentFor` AND you follow a convention where the first parameter label wouldn’t be in the same line as the method name.

Sometimes, one need to find *all* invocations of a method. It maybe is not common. But we’re not always able to write a perfect test suite that makes refactoring an always successful trial and error process. Sometimes we have to think hard, and look at code thoroughly. In this context, a poor signal/noise ratio does not help when you look for something in your code. Searchability is important. If will suffer with the new conventions.

But it’s only a tooling problem.

Gwendal

···

Le 11 févr. 2016 à 15:06, Radosław Pietruszewski <radexpl@gmail.com> a écrit :

This goes against Xcode automatic indentation: it will blow your example code into a white space chaos.

But maybe you are using other tools. With Xcode, a serious tool that deserves consideration as much as critics, the only pragmatic way to invoke a function using several lines is the following:

  attachmentFor(
      image: …,
      extraParam: ….)

Oh, and this is not an edge case. Just look at UIView animation methods.

Gwendal

···

Le 11 févr. 2016 à 15:06, Radosław Pietruszewski <radexpl@gmail.com> a écrit :

Besides — this seems like an edge case anyway. I very rarely see invocations long enough to be compelled to split it into multiple lines, and even if I would, I’d do it like this:

  attachmentFor(image: …,
        extraParam: ….)

Ignore that. I forgot the requirement that it read like a sentence.

Agree that basing the preposition location on whether there is a default value is unfortunate. The problem is "Zone" is not redundant/needless when calling it with the default value.

copyWith()

If I were asking "what zone?" Ok it's the default zone, but I'm just asking "with what?"

···

On Feb 7, 2016, at 10:48, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Sat Feb 06 2016, Douglas Gregor <swift-evolution@swift.org> wrote:

On Feb 6, 2016, at 10:08 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Sat Feb 06 2016, Thorsten Seitz <swift-evolution@swift.org> wrote:

So the preposition should move into the argument label if the argument is optional?

copy(withZone: zone = nil)

That's a good idea.

It seems unfortunate that the placement of the preposition should
change depending on whether there is a default argument or not,
especially since it is reasonable to imagine that an API evolves to
gain a default argument later on.

You're right; it would complicate the rules significantly, too.

   - Doug

-Thorsten

Am 06.02.2016 um 14:45 schrieb Matthew Judge via swift-evolution >>>>> <swift-evolution@swift.org>:

Very first method

copyWith(zone: Zone = nil)

can be called as

copyWith()

I'm assuming this is still something we don't want right?

On Feb 6, 2016, at 02:16, Douglas Gregor via swift-evolution >>>>>> <swift-evolution@swift.org> wrote:

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

Given all the awesome feedback I've gotten on this thread, I went back
to the drawing board and came up with something new; I think this one
works. The previously-stated goals still apply:

[snip goals]

P.S. Doug is presently working on generating new importer results, based
  on these guidelines, for your perusal. They should be ready soon.

Here’s a link:

   Split first selector piece into base name/first argument label. by DougGregor · Pull Request #10 · apple/swift-3-api-guidelines-review · GitHub

Feedback welcome!

   - Doug

_______________________________________________
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

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

--
-Dave

_______________________________________________
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

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