- Proposal: SE-0118
- Authors: Dave Abrahams, Dmitri Gribenko, Maxim Moiseev
- Review Manager: Chris Lattner
- Status: Implemented (Swift 3.0)
- Decision Notes: Rationale
- Bug: SR-2072
- v1 (as proposed)
- v2: fixed spelling of identifiers containing
Utf8
to readUTF8
per convention.
We propose a revision to the names and argument labels of closure parameters in standard library APIs.
Swift-evolution thread: Take 2: Stdlib closure argument labels and parameter names
Discussion of earlier revision of the proposal: Stdlib closure argument labels and parameter names
The names and argument labels of the standard library's closure parameters have been chosen haphazardly, resulting in documentation comments that are inconsistent and often read poorly, and in code completion/documentation that is less helpful than it might be. Because of trailing closure syntax, the choice of argument labels for closures has less impact on use-sites than it might otherwise, but there are many contexts in which labels still do appear, and poorly-chosen labels still hurt readability.
The table below summarizes how this proposal changes usage of the APIs in question.
Before | After |
---|---|
s.withUTF8Buffer(invoke: processBytes) |
s.withUTF8Buffer(processBytes) |
lines.split( isSeparator: isAllWhitespace) |
lines.split( whereSeparator: isAllWhitespace) |
words.sort(isOrderedBefore: >) |
words.sort(by: >) |
words.sorted(isOrderedBefore: >) |
words.sorted(by: >) |
smallest = shapes.min( isOrderedBefore: haveIncreasingSize) |
smallest = shapes.min( by: haveIncreasingSize) |
largest = shapes.max( isOrderedBefore: haveIncreasingSize) |
largest = shapes.max( by: haveIncreasingSize) |
if a.lexicographicallyPrecedes( b, isOrderedBefore: haveIncreasingWeight) |
if a.lexicographicallyPrecedes( b, by: haveIncreasingWeight) |
ManagedBuffer<Header,Element>.create( minimumCapacity: 10, initialValue: makeHeader) |
ManagedBuffer<Header,Element>.create( minimumCapacity: 10, makingValueWith: makeHeader) |
if roots.contains(isPrime) { |
if roots.contains(where: isPrime) { |
if expected.elementsEqual( actual, isEquivalent: haveSameValue) |
if expected.elementsEqual( actual, by: haveSameValue) |
if names.starts( with: myFamily, isEquivalent: areSameExceptForCase) { |
if names.starts( with: myFamily, by: areSameExceptForCase) { |
let sum = measurements.reduce(0, combine: +) |
let sum = measurements.reduce(0, +) |
UTF8.encode( scalar, sendingOutputTo: accumulateByte) |
UTF8.encode( scalar, into: accumulateByte) |
Note: this summary does not illustrate parameter name changes that have also been made pervasively and have an effect on usability of documentation and code completion. Please see the diffs for examples of those.
A complete patch, showing API, documentation, and usage changes, is available for review at https://github.com/apple/swift/pull/2981/files.
This change will break code that depends on the current argument labels. Availability annotations can be used make correcting this breakage a normal part of the migration process.
The initial proposal used much more-verbose labels that were designed to be very explicit about the required semantics of the closure parameters. That information, however, is mostly useful to the author of the call, and, we found, didn't do much to enhance readability at the point of use.
The process of making these changes revealed that there are compelling
arguments for diverging from terms-of-art for the standard functional
methods. For example, the polarity of the argument to filter
would
be crystal clear if it were renamed to where
, and the description of
the semantics of reduce
in the documentation strongly suggest that
accumulated
might be an improvement. Changing the names of these
methods should be considered in a separate proposal.