[swift-evolution] API Guidelines Update

Dave Abrahams dabrahams at apple.com
Wed Feb 24 17:06:18 CST 2016


on Wed Feb 24 2016, David Owens II <swift-evolution at swift.org> wrote:

>> On Feb 24, 2016, at 11:25 AM, Dave Abrahams via swift-evolution
>> <swift-evolution at swift.org> wrote:
>> 
>> 
>> on Wed Feb 24 2016, David Owens II <swift-evolution at swift.org> wrote:
>
>> 
>>>> On Feb 22, 2016, at 11:02 AM, Jordan Rose via swift-evolution
>>>> <swift-evolution at swift.org> wrote:
>>>> 
>>>> In case it's been lost in all the discussion, the -ing/-ed rule is
>>>> essentially the rule Objective-C uses, minus the noun labels for the
>>>> return value and types and the word "by". It's definitely very
>>>> different grammatically from most other API guidelines, but so are
>>>> Objective-C's guidelines.
>>>> 
>>> 
>>> Sure, but I'd actually argue that the noun-labels in ObjC are what
>>> actually provide the context of the non-mutating nature of the
>>> function. 
>> 
>> I disagree with that assertion.  The nouns tell you what type is going
>> to be returned and what type is being passed, not whether there will be
>> mutation to the receiver.
>
> The noun tells you the object that will be worked with.
>
> `stringByTrimmingCharactersInSet(_:)` - return a string by trimming characters in set
>
> `trimCharactersInSet(_:)`, `trim(_:)`, and `trimming(_:)` all read:
> return myself by trimming characters in set; there is no noun, so it
> is implied that it's the caller of the function.

I disagree. The first two form imperative verb phrases, and do not imply
to me that anything will be returned.  Furthermore, I think for anyone
who works in a language with mutation it is natural to assume that
imperative-verb-phrase methods might mutate the receiver and return
nothing.  This is not a new idea; Cocoa already does things this way.

> The first two guidelines already captures this sentiment as well:
>
>   1. "Those without side-effects should read as noun phrases".
>   2. "Those with side-effects should read as imperative verb phrases."

I know what the guidelines say and what they're supposed to mean, and I
can't see how they support your point in any way.  Neither “trimming b”
nor “a trimming b” is an imperative verb phrase in English.  It is
always a noun phrase.

>>> I think we are opening ourselves up to the potential of many confusing
>>> APIs when an -ed/-ing form of a function name is an appropriate
>>> candidate with the opposite meaning that the guidelines set out.
>>> 
>>> The -ed/-ing suffix choice doesn't seem outright bad, but it does seem
>>> to be "death by paper cuts" bad, at least to me. The guidelines are
>>> already a bit complicated in this area. Also, like others, I find the
>>> -ing suffix to imply a state of work to be done that will be completed
>>> later or cover an extended amount of time; mutation has no bearing on
>>> the implementation choice here.
>>> 
>>> Side note: the guidelines are also unintentionally narrow: "Use the
>>> “ed/ing” rule to name the nonmutating counterpart of a mutating
>>> method."
>>> 
>>> We should *always* be following this pattern regardless of the
>>> existence of a nonmutating counterpart. Otherwise, if you implement
>>> just a non-mutating function for sorting without the counterpart, you
>>> need to use a noun-phrase, like `sortBy`. Then if you later add a
>>> mutating version, you need to rename the `sortBy` to `sorted`. That
>>> seems like the wrong outcome of the guidelines.
>> 
>> I think you're confused: `sortBy(x)`—or more properly, `sort(by:
>> x)`—isn't a noun-phrase; it's an imperative verb phrase, so it would be
>> an ineligible form for a nonmutating method call.
>
> I think you threw out the baby with the bathwater because of a
> technicality there. Let's try again.

OK.

> The stages of an API development process might look like this:
>
> version 1: "Those without side-effects should read as noun phrases"
>
> func contentsOf(filter:) -> Self  // returns a copy
>
> version 2: "Those with side-effects should read as imperative verb phrases"
>
> func contentsOf(filter:) -> Self  // returns a copy
> mutating func filter(by:)         // honestly, I'm not sure where the preposition debate has landed...
>
> version 3, bug comes in that the API doesn't meet the guidelines.
>
> func filtered(by:) -> Self  // returns a copy
> mutating func filter(by:)
>
> Unless I'm misunderstanding the guidelines, this is the natural
> progression of the API (minus the `by` preposition, which is
> irrelevant to this discussion).
>
> In my opinion, the guidelines should not lead us down breaking API
> changes as the API evolves. The entire -ed/-ing confuses the entire
> section, and requires future knowledge of what the future API will
> look like beforehand. This circles back to my first point about the
> noun actually serving as more information that the type.

Yes, that's true.  You have to think ahead about API evolution if you
don't want to break users.  That goes for naming as well as anything
else.  If I said, “related APIs should form a distinguishable family,”
you probably wouldn't argue (would you?) but that guideline could lead
to exactly the same sequence of events.

-- 
-Dave



More information about the swift-evolution mailing list