[Review] SE-0023 API Design Guidelines

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.

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.

...unless it falls into one of the other categories (such as “copy” and
autorelease methods, methods which initiate an action and return a
result, etc.) that makes it ineligible to be a property.

···

on Mon Feb 01 2016, Alex Migicovsky <migi-AT-apple.com> wrote:

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:

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

--
-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(?)

That would also be great. Although I still think including it in the book would
be more effective. Not everyone is going to follow a link and split their attention
between two documents...
Would it be possible to include the guidelines and preface them with a note that
the most up-to date version can always be found on the web with the link there?

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

Fair enough :-)

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

I certainly agree that that should be the goal (to have basic guidelines that is,
although preserving your sanity is a close second ;-))

What is the plan in this area; will this be a future discussion/proposal to amend
the guidelines?

I was wondering whether it might make sense to have a separate thread collect
"rules" and guidelines in this area from the community to see what's out there
in the hope of eventually paring them down to some useful essentials...

--
-Dave

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

- Janosch

···

On 02 Feb 2016, at 01:26, 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:

That's reminiscent of the way the classic Cocoa naming guidelines cleverly avoided these issues by using the 'did-' prefix consistently instead of ever conjugating verbs into preterite tense. 'after' is a bit awkward, though, as are any other equivalent prefixes i can think of that have the same effect on the past participle (havingSplit? bySplitting?)

-Joe

···

On Jan 22, 2016, at 1:57 PM, Jeff Kelley via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 22, 2016, at 4:53 PM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

How do you handle naming non-mutating versions of these operations? Conjugating other irregular verbs also imposes a barrier on developers whose first language is not English.

Swift could use “after” as a prefix, or something similar.

array.sort()
array.afterSort()

I was tempted to say “afterSorting()” but that has the same problems mentioned above.

Ideally solution to this problem should also handle sets properly. That
is,

  x.union(y)

is non-mutating and returns a new set. Then you need a way to name the
version that does an in-place union.

···

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

On Jan 22, 2016, at 1:57 PM, Jeff Kelley via swift-evolution >> <swift-evolution@swift.org> wrote:

On Jan 22, 2016, at 4:53 PM, Joe Groff via swift-evolution >>> <swift-evolution@swift.org > >>> <mailto:swift-evolution@swift.org>> >>> wrote:

How do you handle naming non-mutating versions of these operations?
Conjugating other irregular verbs also imposes a barrier on
developers whose first language is not English.

Swift could use “after” as a prefix, or something similar.

array.sort()
array.afterSort()

I was tempted to say “afterSorting()” but that has the same problems mentioned above.

That's reminiscent of the way the classic Cocoa naming guidelines
cleverly avoided these issues by using the 'did-' prefix consistently
instead of ever conjugating verbs into preterite tense. 'after' is a
bit awkward, though, as are any other equivalent prefixes i can think
of that have the same effect on the past participle (havingSplit?
bySplitting?)

--
-Dave

Where this rule feels clumsy to me is in code such as

func loginWithUsername(username: String, password: String) -> Bool

vs.

func login(username: String, password: String) -> Bool

But maybe it just takes some time to get used to the style.

···

On Sat, Jan 23, 2016 at 12:00 AM, David Owens II via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Compensate For Weak Type Information as needed to clarify a parameter’s role.

Especially when a parameter type is NSObject, Any, AnyObject, or a fundamental type such Int or String, type information and context at the point of use may not fully convey intent. In this example, the declaration may be clear, but the use site is vague:

func add(observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // vague

To restore clarity, precede each weakly-typed parameter with a noun describing its role:

func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear

How would we apply this to delegate patterns?
For example, would we keep tableview(tableView:cellForRowAtIndexPath:), or would we switch to delegate(tableView:cellForRowAtIndexPath:) ?
Or perhaps better, for clarity over which protocol is being conformed to / which property of the delegator is calling the function:
dataSource(tableView:cellForRowAtIndexPath:),
delegate(tableView:didSelectRowAtIndexPath:)

There would be no argument label for `tableView`; it’s a needless word and there is a strong type information: it’s a TableView.

Weak type information would be like “key path” below. Yes, it’s String, but it’s actually a specially crafted string that takes the form: “some.nested.values”. A string like “some+234+//23” is not going to work.

I’m also not really convinced that `removeAt(position: Int)` doesn’t actually fall under both rules. The first parameter is a weak type; it has rules associated with it (non-zero and less than collection size). In the guidelines, it could be argued that it should be `removeAtIndex(position: Int)`. I’d prefer the `removeAt(index position: Int)` version. But, you can kinda make the weak type argument for a lot of scenarios… It’s a little ambiguous to me.

-David

···

On Jan 22, 2016, at 4:12 PM, Ross O'Brien <narrativium@gmail.com> wrote:

On Sat, Jan 23, 2016 at 12:00 AM, David Owens II via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Compensate For Weak Type Information as needed to clarify a parameter’s role.

Especially when a parameter type is NSObject, Any, AnyObject, or a fundamental type such Int or String, type information and context at the point of use may not fully convey intent. In this example, the declaration may be clear, but the use site is vague:

func add(observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // vague

To restore clarity, precede each weakly-typed parameter with a noun describing its role:

func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear

I don’t understand why to compensate for weak type information we put some of that compensation in the name of the function and other parts of it in the [external] name of the parameter.

If we were going to reference functions like this: addObserver:forKeyPath, then I can understand it. But that’s not the plan of record, it’s to do this: addObserver(_:forKeyPath).

Regardless of the default naming scheme, it seems like the rule should be to use external names to clarify that parameters role.

func add(observer observer: NSObject, forKeyPath path: String)
grid.add(observer: self, forKeyPath: graphics)

This promotes a very clear and consistent rule: weak type information should be clarified by the parameter’s external name. There are no exceptions for the first parameter. Otherwise, it seems like there is super fine line between this rule and the next one below.

Additionally, this also alleviates my concerns with the default parameter have _ as the external name by default because this addresses the case when it would be desirable to have that name. Further, the case below handles the case when it’s not.

Omit Needless Words. Every word in a name should convey salient information at the use site.

More words may be needed to clarify intent or disambiguate meaning, but those that are redundant with information the reader already possesses should be omitted. In particular, omit words that merely repeat type information:

public mutating func removeElement(member: Element) -> Element?
allViews.removeElement(cancelButton)

In this case, the word Element adds nothing salient at the call site. This API would be better:

public mutating func remove(member: Element) -> Element?
allViews.remove(cancelButton) // clearer

Occasionally, repeating type information is necessary to avoid ambiguity, but in general it is better to use a word that describes a parameter’s role rather than its type. See the next item for details.

The description here seems to overlap with the “Compensate for Weak Type Information” rule, especially with the clause: “repeating type information”. It may be better to re-work the example to be `removeItem(member: Element)` to make this distinction more clear that it’s not type information being removed.

Also, by clarifying that statement, the above rule change I suggested would be consistent. Type information clarification goes into the external parameter name, functionality clarification goes into the function name. Those are hard-n-fast rules that are straight-forward.

Be Grammatical

When a mutating method is described by a verb, name its non-mutating counterpart according to the “ed/ing” rule, e.g. the non-mutating versions of x.sort() and x.append(y) are x.sorted() and x.appending(y).

Is this guideline suggesting that we should design our APIs to generally have both mutating and non-mutaging counterparts?

As other have pointed out, this is also very hard to do all the time. I think the alternatives are worse. It would be nice if there were a way to annotate all member functions as mutating/non-mutating to really by-pass this ambiguity.

Other than the above, the proposal looks pretty good to me.

-David

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

I much prefer the second version:

func login(username name: String, password: String) -> Bool
login(username: “bob”, password: “1234”)

-David

···

On Jan 22, 2016, at 4:26 PM, Michael Wells via swift-evolution <swift-evolution@swift.org> wrote:

On Sat, Jan 23, 2016 at 12:00 AM, David Owens II via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Compensate For Weak Type Information as needed to clarify a parameter’s role.

Especially when a parameter type is NSObject, Any, AnyObject, or a fundamental type such Int or String, type information and context at the point of use may not fully convey intent. In this example, the declaration may be clear, but the use site is vague:

func add(observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // vague

To restore clarity, precede each weakly-typed parameter with a noun describing its role:

func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear

Where this rule feels clumsy to me is in code such as

func loginWithUsername(username: String, password: String) -> Bool

vs.

func login(username: String, password: String) -> Bool

But maybe it just takes some time to get used to the style.

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

Current:

* Use imperative verb phrases for mutating methods: x.reverse(), x.sort(), x.tweak()
* Use noun phrases for non-mutating methods: x.distanceTo(...), idx.successor()

Proposed:

* Use verb phrases to declare procedural methods, whether or not they mutate an instance or just produce side
   effects: x.reverse(), x.sort(), x.tweak(), x.perform(), x.dispatch(), x.send()
* Use noun phrases to describe values returned by a functional method: x.distanceTo(y), index.successor() (This
   admittedly leaves further issues around other functional methods, for example, seq.separatedBySequence(seq) and
    int.strideTo(other: Self, step:Self.Stride), etc. )

I suggest that mutating methods are just a procedural method (side effect, no return value) vs functional.

Hi Erica,

When you propose a change, could you please explain why you think your
change is an improvement?

Thanks,
Dave

I believe the current distinction is misguided in focusing on mutating and non-mutating implementations when the
differentiation can be viewed from a more general level. There are two ways to distinguish these:

* Does this method or function have side effects (which is what the current API approach intends to address); and
* Is this method or function inherently functional or procedural in nature, returning a value or not.

For example, contrast sort() and sortInPlace(). Even with the current approach they lack a natural clarity. You could easily swap
them without anything "breaking" in understanding because your solution is conventional, not based on any underlying principle.

With noun/verb naming, the function name reflects the functional/procedural underlying differentiation.
* A function produces something: f(x) -> y.
* A procedure does something: g(x) -> Void

Under my proposed change, the procedural variation would be sort, sortInPlace, etc. Optional adverbs and near-adverbs
could distinguish similar versions sortQuickly, sortBalanced, etc.

The functional would be sortedVersion or with a slight rule tweak that infers the subject of the action, sorted. The adjective modifies a noun, and
therefore implies the presence of a noun that is not explicitly added to the name.

I find my approach more principled and more obvious for use to non-native speakers.

Hopefully this clarifies.

-- E, finishing dinner and about to go on family time. I'll be around a little longer but not much longer

···

On Jan 22, 2016, at 4:24 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Fri Jan 22 2016, Erica Sadun <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-- E

   On Jan 22, 2016, at 2: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

    What 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

Current: Use imperative verb phrases for mutating methods: x.reverse(), x.sort(), x.tweak() Use noun phrases for
non-mutating methods: x.distanceTo(...), idx.successor() Proposed: Use verb phrases to declare procedural methods,
whether or not they mutate an instance or just produce side effects: x.reverse(), x.sort(), x.tweak(), x.perform(),
x.dispatch(), x.send() Use noun phrases to describe values returned by a functional method: x.distanceTo(y),
index.successor() (This admittedly leaves further issues around other functional methods, for example,
seq.separatedBySequence(seq) and int.strideTo(other: Self, step:Self.Stride), etc. ) I suggest that mutating
methods are just a procedural method (side effect, no return value) vs functional. -- E > On Jan 22, 2016, at 2:02
PM, 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 > What 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

--
-Dave

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

Consider an exception rule:

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

login(username: String, password:String)
moveTo(x: Double, y: Double)

but

addLineToPoint(p1: CGPoint, withThickness: CGFloat)

-- Erica

···

On Jan 22, 2016, at 5:26 PM, Michael Wells via swift-evolution <swift-evolution@swift.org> wrote:

On Sat, Jan 23, 2016 at 12:00 AM, David Owens II via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Compensate For Weak Type Information as needed to clarify a parameter’s role.

Especially when a parameter type is NSObject, Any, AnyObject, or a fundamental type such Int or String, type information and context at the point of use may not fully convey intent. In this example, the declaration may be clear, but the use site is vague:

func add(observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // vague

To restore clarity, precede each weakly-typed parameter with a noun describing its role:

func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear

Where this rule feels clumsy to me is in code such as

func loginWithUsername(username: String, password: String) -> Bool

vs.

func login(username: String, password: String) -> Bool

But maybe it just takes some time to get used to the style.

What I like about the inPlace suffix is

(1) it makes it clear that a mutating variant is being used and
(2) the bulk of inPlace pushes us in the direction of non-mutating versions.

In early Swift I believe the names were sort and sorted and I could never remember which is which (yes, of course the signature makes that clear) but sort vs sortInPlace seems more clear to me as a consumer of an API.

That said, once a naming convention is settled - it will be easy enough to reason about as the guidelines will be clear.

Daniel

···

On Jan 22, 2016, at 6:17 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

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

     + When a mutating method is described by a verb, name its
     non-mutating counterpart according to the “ed/ing” rule,
     e.g. the non-mutating versions of x.sort() and x.append(y) are
     x.sorted() and x.appending(y).

This is a nice rule in theory, but English fights it with the full
fury of its irregularity. There are a lot of common operations whose
past tense shares a spelling with the infinitive—'split', 'cut',
'read', and 'cast' immediately come to mind. How do you handle naming
non-mutating versions of these operations? Conjugating other irregular
verbs also imposes a barrier on developers whose first language is not
English.

Agreed. There are also operations that are not naturally verbs. That's
why we still haven't changed unionInPlace in SetAlgebraType, for
example. The “InPlace” suffix convention is the best thing I've come up
with for handling these scenarios.

--
-Dave

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

+1 for me too.

func login(username name: String, password: String) -> Bool
login(username: “bob”, password: “1234”)

It feels much more consistent and simpler.

···

On Jan 22, 2016, at 7:47 PM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 22, 2016, at 4:26 PM, Michael Wells via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Sat, Jan 23, 2016 at 12:00 AM, David Owens II via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Compensate For Weak Type Information as needed to clarify a parameter’s role.

Especially when a parameter type is NSObject, Any, AnyObject, or a fundamental type such Int or String, type information and context at the point of use may not fully convey intent. In this example, the declaration may be clear, but the use site is vague:

func add(observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // vague

To restore clarity, precede each weakly-typed parameter with a noun describing its role:

func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear

Where this rule feels clumsy to me is in code such as

func loginWithUsername(username: String, password: String) -> Bool

vs.

func login(username: String, password: String) -> Bool

But maybe it just takes some time to get used to the style.

I much prefer the second version:

Guess everything is ok now...
login(username: “bob”, password: “1234”)

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

Where this rule feels clumsy to me is in code such as

func loginWithUsername(username: String, password: String) -> Bool

vs.

func login(username: String, password: String) -> Bool

But maybe it just takes some time to get used to the style.

You're right that loginWithUsername is clumsy, since the first argument is
probably an expression like "username" or "usernameField.text" or somesuch.
But I would much prefer

    func loginAs(username: String, password: String) -> Bool

because it reads like something I'd actually say. Consider telling a
coworker "log in as 'mayoff', password 'bikeshed'".

How would we apply this to delegate patterns?
For example, would we keep tableview(tableView:cellForRowAtIndexPath:), or would we switch to delegate(tableView:cellForRowAtIndexPath:) ?
Or perhaps better, for clarity over which protocol is being conformed to / which property of the delegator is calling the function:
dataSource(tableView:cellForRowAtIndexPath:),
delegate(tableView:didSelectRowAtIndexPath:)

FWIW, I am personally favorable to a more radical-renaming for delegate methods, roughly the below:

func numberOfSections(inTableView tableView: UITableView) -> Int // <- against guidelines, but symmetric
func numberOfRows(inTableView tableView: UITableView, forSection section: Int) -> Int
func cellForRow(inTableView tableView: UITableView, atIndexPath indexPath: NSIndexPath) -> UITableView

…where the rule is to find the “what is this method about” part of the selector, make that the name of the Swift function, and then label each argument as-necessary; the goal is for the methods to read as approximate natural-language sentences.

This is most definitely *not* in line with conventions, but I have found it to be *much* more readable overall; this is especially true in the case of new APIs (which don’t have the benefit of deep familiarity like the table-view and similar).

EG, consider the following lightly-edited definition (from some Swift code that needs to be usable from Objective-C):

// from a `TransitionAnimatorDelegateProtocol`
@objc(transitionAnimator:userInfoForTransitionSender:transitionOrigin:transitionDestination:)
  func transitionUserInfo(
    forAnimator animator: TransitionAnimator,
    sender: AnyObject?,
    origin: TransitionOriginProtocol,
    destination: TransitionDestinationProtocol) -> [String:AnyObject]?

…which, coming across in Swift, feels a whole lot more readable than the “conventional” approach; I mean really, would anyone out there voluntarily use a name like the below, instead:

func transtionAnimator(
  animator: TransitionAnimator,
  userInfoForTransitionSender sender: AnyObject?,
  transitionOrigin origin: TransitionOriginProtocol,
  transitionDestination destination: TransitionDestination) -> [String:AnyObject]?

…except out of respect for tradition?

I’m still processing the overall guidelines.

···

On Jan 22, 2016, at 6:12 PM, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

On Sat, Jan 23, 2016 at 12:00 AM, David Owens II via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Compensate For Weak Type Information as needed to clarify a parameter’s role.

Especially when a parameter type is NSObject, Any, AnyObject, or a fundamental type such Int or String, type information and context at the point of use may not fully convey intent. In this example, the declaration may be clear, but the use site is vague:

func add(observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // vague

To restore clarity, precede each weakly-typed parameter with a noun describing its role:

func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear

I don’t understand why to compensate for weak type information we put some of that compensation in the name of the function and other parts of it in the [external] name of the parameter.

If we were going to reference functions like this: addObserver:forKeyPath, then I can understand it. But that’s not the plan of record, it’s to do this: addObserver(_:forKeyPath).

Regardless of the default naming scheme, it seems like the rule should be to use external names to clarify that parameters role.

func add(observer observer: NSObject, forKeyPath path: String)
grid.add(observer: self, forKeyPath: graphics)

This promotes a very clear and consistent rule: weak type information should be clarified by the parameter’s external name. There are no exceptions for the first parameter. Otherwise, it seems like there is super fine line between this rule and the next one below.

Additionally, this also alleviates my concerns with the default parameter have _ as the external name by default because this addresses the case when it would be desirable to have that name. Further, the case below handles the case when it’s not.

Omit Needless Words. Every word in a name should convey salient information at the use site.

More words may be needed to clarify intent or disambiguate meaning, but those that are redundant with information the reader already possesses should be omitted. In particular, omit words that merely repeat type information:

public mutating func removeElement(member: Element) -> Element?
allViews.removeElement(cancelButton)

In this case, the word Element adds nothing salient at the call site. This API would be better:

public mutating func remove(member: Element) -> Element?
allViews.remove(cancelButton) // clearer

Occasionally, repeating type information is necessary to avoid ambiguity, but in general it is better to use a word that describes a parameter’s role rather than its type. See the next item for details.

The description here seems to overlap with the “Compensate for Weak Type Information” rule, especially with the clause: “repeating type information”. It may be better to re-work the example to be `removeItem(member: Element)` to make this distinction more clear that it’s not type information being removed.

Also, by clarifying that statement, the above rule change I suggested would be consistent. Type information clarification goes into the external parameter name, functionality clarification goes into the function name. Those are hard-n-fast rules that are straight-forward.

Be Grammatical

When a mutating method is described by a verb, name its non-mutating counterpart according to the “ed/ing” rule, e.g. the non-mutating versions of x.sort() and x.append(y) are x.sorted() and x.appending(y).

Is this guideline suggesting that we should design our APIs to generally have both mutating and non-mutaging counterparts?

As other have pointed out, this is also very hard to do all the time. I think the alternatives are worse. It would be nice if there were a way to annotate all member functions as mutating/non-mutating to really by-pass this ambiguity.

Other than the above, the proposal looks pretty good to me.

-David

_______________________________________________
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
https://lists.swift.org/mailman/listinfo/swift-evolution

I would definitely prefer the second style as well although maybe that's
just because I'm used to it.

···

On Sat, Jan 23, 2016 at 12:34 AM, Charles Kissinger <crk@akkyra.com> wrote:

On Jan 22, 2016, at 3:59 PM, Trent Nadeau via swift-evolution < > swift-evolution@swift.org> wrote:

Under "Follow case conventions", how should acronyms (like "HTML") be
handled: HTMLElement or HtmlElement?

I would certainly prefer the second style. Unless the acronym comes at the
end of the identifier, it is more readable when only the first letter of
the acronym is uppercase, IMO. Otherwise the acronym merges with the
capitalized first letter of the following word.

Using all caps for acronyms also doesn’t work very well at the start of a
variable name, leading to:

var hTMLElement = HTMLElement()

versus:

var htmlElement = HtmlElement()

--CK

On Fri, Jan 22, 2016 at 4: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

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

--
Trent Nadeau

They aren't, though. I don't see much value in setting false expectations.

-Joe

···

On Jan 23, 2016, at 10:24 AM, Trent Nadeau <tanadeau@gmail.com> wrote:

I think it makes sense for enum cases to be UpperCamelCase as they can be thought of as scoped types (singleton types in the case of cases with no associated types).

"splitting" works perfectly well on its own, IMO. If there's an
argument to the method, you'll want some kind of preposition like "At"
or "On" afterwards.

I think the real problem cases for this guideline as written are the
ones where there's no underlying verb, like "union", or where the verb
already has a strong non-mutating connotation, like "exclusiveOr."
Those are the ones that really cry out for a different convention, like
"InPlace."

In developing the guidelines, we had some internal arguments about
whether it was worth adding complexity to accomodate those cases, or
whether we should simply not mention them and let them get sorted out on
a case-by-case basis when they come up in code review. We didn't reach
consensus, so this would be a useful area in which to get community
input.

···

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

On Jan 22, 2016, at 1:57 PM, Jeff Kelley via swift-evolution >> <swift-evolution@swift.org> wrote:

On Jan 22, 2016, at 4:53 PM, Joe Groff via swift-evolution >>> <swift-evolution@swift.org > >>> <mailto:swift-evolution@swift.org>> >>> wrote:

How do you handle naming non-mutating versions of these operations?
Conjugating other irregular verbs also imposes a barrier on
developers whose first language is not English.

Swift could use “after” as a prefix, or something similar.

array.sort()
array.afterSort()

I was tempted to say “afterSorting()” but that has the same problems mentioned above.

That's reminiscent of the way the classic Cocoa naming guidelines
cleverly avoided these issues by using the 'did-' prefix consistently
instead of ever conjugating verbs into preterite tense. 'after' is a
bit awkward, though, as are any other equivalent prefixes i can think
of that have the same effect on the past participle (havingSplit?
bySplitting?)

--
-Dave

What about enums with associated data? Those really are like types. So do we capitalize those?

Unless those get redesigned, there is really this contrary feel to those and other enum cases.

···

Sent from my iPhone

On Jan 23, 2016, at 10:49 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 23, 2016, at 10:24 AM, Trent Nadeau <tanadeau@gmail.com> wrote:

I think it makes sense for enum cases to be UpperCamelCase as they can be thought of as scoped types (singleton types in the case of cases with no associated types).

They aren't, though. I don't see much value in setting false expectations.

-Joe

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

Before open sourcing, I had written up some thoughts on this:

From an API perspective, an enum 'case' behaves similarly to a factory method or initializer on a struct or class, and in native Swift we generally prefer `init`s to static factory methods when possible. We also see a lot of API design in the wild where framework authors paper over the enum-ness of their API enums with initializers:

enum Result<T> {
  case Success(T)
  case Error(ErrorType)

  init(success: T) { self = .Success(success) }
  init(error: ErrorType) { self = .Error(error) }
}

We hadn't settled on our argument label model when we originally designed and implemented enums; I feel like if we had, it's likely we would have favored cases that natively look and feel more like initializers, using labels to distinguish cases:

enum Result<T> {
  case (success: T)
  case (error: ErrorType)
}

-Joe

···

On Jan 23, 2016, at 11:01 AM, David Owens II <david@owensd.io> wrote:

What about enums with associated data? Those really are like types. So do we capitalize those?

Unless those get redesigned, there is really this contrary feel to those and other enum cases.

Many of Java's interfaces also conform to the standard swift uses, with things like runnable/comparable. Those define capabilities and are named with the same reasoning that the api guidelines propose, so it's easy to infer that they are interfaces from the name. I haven't worked in Java in a while so I could be forgetting other interfaces that don't follow this trend though, but interfaces in Java are more easily swapped with classes than protocols are in swift anyways (since protocols with associated types cannot be used as the type of a variable or whatnot).

···

--
Kevin Lundberg

On Jan 23, 2016, at 10:27 AM, Haravikk <me@haravikk.com> wrote:

Since I learned object-oriented programming in Java, I never understood the need for suffixes and prefixes at all, as Java’s package system makes for very simple namespaces for everything in the event that simply using a class/interface name is unclear.

I’d say that personally I don’t see why CollectionType shouldn’t just be Collection, in cases where several things are named Collection we should really have some kind of disambiguation mechanism anyway, perhaps with some special cases for specifying when you want a protocol rather than a class/struct.

In my ideal world every language would would follow Java’s example on name-spaces, while avoiding emulating its horrific security record ;)

On 23 Jan 2016, at 14:52, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

I never liked the convention of distinguishing between interfaces and classes by prepending an „I“ for interfaces in other languages and I’m not overly fond fond of the suffix „Type“ currently used in Swift protocols.
This is the same as prefixing (or suffixing) variable names with something to express their type, e.g. `String sName` or `int iLength`.
That’s what we have type information for.

And because of the substitution principle it should make no difference whether I have a protocol or a struct or class. What is a `CollectionType` vs. a `Collection`? Is it the type of a `Collection`, i.e. a meta type? Why not simply `Collection` if it describes what a collection is?
I guess its often more the problem of finding a suitable different name for the implementation and that’s why I sometimes wonder whether it might make sense to give protocols their own namespace…

In short, I am not fond of the suffix „Type“ (but I would dislike the suffix „Protocol“ or prefixes like „I“ or „P“ even more).

I’m open to debate, though :-)

-Thorsten

Am 23.01.2016 um 06:25 schrieb Kevin Lundberg via swift-evolution <swift-evolution@swift.org>:

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

I personally like the idea behind the current convention for protocols that describe a thing (IntegerType, CollectionType, etc) where there is a suffix of Type appended to the end, so I give this specific part of the proposal a -1. The specific wording of the protocol's name is not so important as the recognition at a glance that this is a protocol vs a concrete type. I like being able to infer at a glance how I'm expected to use a specific type reference based on its name alone; otherwise I may have to refer back to the type definition to refresh my memory of whether or not it is in fact a protocol or is something else.

This change could also lead to confusion among some developers. For someone who is new to Swift, would they know they should use Bool over Boolean if they've seen both types before? Both names look reasonable to store a boolean value, but the semantics of each type differ significantly. Someone may try to have a type conform to Bool instead of Boolean, which would obviously not work, but could cause some consternation for developers who don't know the difference by heart. Naming the protocol BooleanType at least calls out that this may not be conceptually the same as a plain boolean value, which could make a developer think twice before trying to use that over Bool.

Removing some common prefix from these kinds of protocols could also run the risk of unintentionally shadowing type names, if someone wanted to write their own Collection or Error struct or class for instance, or if a pre-existing concrete type in their code turned out to unexpectedly shadow a protocol in a new dependency that they want to add. These situations would not cause any technical hiccups due to module namespacing, but it could lead to confusion when a developer forgets to qualify the name and tries to use one type where the other is expected.

In short, appending Type (or something like it) i think is a reasonable convention to keep around for non-behavioral protocols.

As far as alternatives to 'Type', I personally don't like the suffix 'Protocol' as much (which is suggested as a disambiguation option in the related standard library review), since 'Type' is shorter, feels nicer to read, and describes the purpose of the protocol well to me. C#'s approach of prefixing all interfaces with a capital I would be even more succinct, but I personally don't think that approach would look nice to read either. (PCollection, PBoolean? Ick.)
_______________________________________________
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

+1 on the CamelCase. Just so y’all know, though, there’s a bug in the complier involving naming collisions between cases and types. Currently (Xcode 7.2), case labels silently override type names, leading to the following error:
enum Foo {
    case Int // Ok
    case Something(Int) // “Error: Use of undeclared type 'Int'"
    case Float(Double) // Ok
}

That should probably get fixed *before* the API design guidelines start recommending that case labels begin with uppercase letters. (I mean, it should get fixed anyway, but it should especially get fixed before we start encouraging behavior which makes it easier to encounter.)

- Dave Sweeris

···

On Jan 23, 2016, at 11:18 AM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 23, 2016, at 11:01 AM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

What about enums with associated data? Those really are like types. So do we capitalize those?

Unless those get redesigned, there is really this contrary feel to those and other enum cases.

Before open sourcing, I had written up some thoughts on this:

https://github.com/apple/swift/blob/master/docs/proposals/EnumStyle.rst

From an API perspective, an enum 'case' behaves similarly to a factory method or initializer on a struct or class, and in native Swift we generally prefer `init`s to static factory methods when possible. We also see a lot of API design in the wild where framework authors paper over the enum-ness of their API enums with initializers:

enum Result<T> {
  case Success(T)
  case Error(ErrorType)

  init(success: T) { self = .Success(success) }
  init(error: ErrorType) { self = .Error(error) }
}

We hadn't settled on our argument label model when we originally designed and implemented enums; I feel like if we had, it's likely we would have favored cases that natively look and feel more like initializers, using labels to distinguish cases:

enum Result<T> {
  case (success: T)
  case (error: ErrorType)
}

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