mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
248 lines
7.3 KiB
ReStructuredText
248 lines
7.3 KiB
ReStructuredText
:orphan:
|
|
|
|
.. default-role:: code
|
|
|
|
=======================================
|
|
Swift Standard Library API Design Guide
|
|
=======================================
|
|
|
|
.. Note:: This guide documents *current practice* in the Swift
|
|
standard library as of April 2015. API conventions are
|
|
expected to evolve in the near future to better harmonize
|
|
with Cocoa.
|
|
|
|
The current Swift Standard Library API conventions start with the
|
|
Cocoa guidelines as discussed on these two wiki pages: [`API
|
|
Guidelines <http://cocoa.apple.com/cgi-bin/wiki.pl?API_Guidelines>`_,
|
|
`Properties <http://cocoa.apple.com/cgi-bin/wiki.pl?Properties>`_],
|
|
and in this `WWDC Presentation
|
|
<http://cocoa.apple.com/CocoaAPIDesign.pdf>`_. Below, we list where
|
|
and how the standard library's API conventions differ from those of
|
|
Cocoa
|
|
|
|
Differences
|
|
===========
|
|
|
|
Points in this section clash in one way or other with the Cocoa
|
|
guidelines.
|
|
|
|
The First Parameter
|
|
-------------------
|
|
|
|
* The first parameter to a function, method, or initializer typically
|
|
does not have an argument label:
|
|
|
|
.. parsed-literal::
|
|
|
|
alligators.insert(fred) // yes
|
|
if alligators.contains(george) { // yes
|
|
return
|
|
}
|
|
|
|
alligators.insert(**element:** fred) // no
|
|
if alligators.contains(**element:** george) { // no
|
|
return
|
|
}
|
|
|
|
* Typically, no suffix is added to a function or method's base name in
|
|
order to serve the same purpose as a label:
|
|
|
|
.. parsed-literal::
|
|
|
|
alligators.insert\ **Element**\ (fred) // no
|
|
if alligators.contains\ **Element**\ (george) { // no
|
|
return
|
|
}
|
|
|
|
|
|
* A preposition is added to the end of a function name if the role of
|
|
the first parameter would otherwise be unclear:
|
|
|
|
.. parsed-literal::
|
|
|
|
// origin of measurement is aPosition
|
|
aPosition.distance\ **To**\ (otherPosition)
|
|
|
|
// we're not "indexing x"
|
|
if let position = aSet.index\ **Of**\ (x) { ... }
|
|
|
|
* Argument labels are used on first parameters to denote special
|
|
cases:
|
|
|
|
.. parsed-literal::
|
|
|
|
// Normal case: result has same value as argument (traps on overflow)
|
|
Int(aUInt)
|
|
|
|
// Special: interprets the sign bit as a high bit, changes value
|
|
Int(**bitPattern**: aUInt)
|
|
|
|
// Special: keeps only the bits that fit, losing information
|
|
Int32(**truncatingBitPattern**: anInt64)
|
|
|
|
Subsequent Parameters
|
|
---------------------
|
|
|
|
* Argument labels are chosen to clarify the *role* of an argument,
|
|
rather than its type:
|
|
|
|
.. parsed-literal::
|
|
|
|
x.replaceSubrange(r, **with:** someElements)
|
|
|
|
p.initializeFrom(q, **count:** n)
|
|
|
|
* Second and later parameters are always labeled except in cases where
|
|
there's no useful distinction of roles::
|
|
|
|
swap(&a, &b) // OK
|
|
|
|
let topOfPicture = min(topOfSquare, topOfTriangle, topOfCircle) // OK
|
|
|
|
Other Differences
|
|
-----------------
|
|
|
|
* We don't use namespace prefixes such as "`NS`", relying instead on
|
|
the language's own facilities.
|
|
|
|
* Names of types, protocols and enum cases are `UpperCamelCase`.
|
|
Everything else is `lowerCamelCase`. When an initialism appears, it
|
|
is **uniformly upper- or lower-cased to fit the pattern**:
|
|
|
|
.. parsed-literal::
|
|
|
|
let v: String.\ **UTF**\ 16View = s.\ **utf**\ 16
|
|
|
|
* Protocol names end in `Type`, `able`, or `ible`. Other type names
|
|
do not.
|
|
|
|
Additional Conventions
|
|
======================
|
|
|
|
Points in this section place additional constraints on the standard
|
|
library, but are compatible with the Cocoa guidelines.
|
|
|
|
* We document the complexity of operations using big-O notation.
|
|
|
|
* In API design, when deciding between a nullary function and a property for a
|
|
specific operation, arguments based on performance characteristics and
|
|
complexity of operations are not considered. Reading and writing properties
|
|
can have any complexity.
|
|
|
|
* We prefer methods and properties to free functions. Free functions
|
|
are used when there's no obvious `self` ::
|
|
|
|
min(x, y, z)
|
|
|
|
when the function is an unconstrained generic ::
|
|
|
|
print(x)
|
|
|
|
and when function syntax is part of the domain notation ::
|
|
|
|
-sin(x)
|
|
|
|
* Type conversions use initialization syntax whenever possible, with
|
|
the source of the conversion being the first argument::
|
|
|
|
let s0 = String(anInt) // yes
|
|
let s1 = String(anInt, radix: 2) // yes
|
|
let s1 = anInt.toString() // no
|
|
|
|
The exception is when the type conversion is part of a protocol::
|
|
|
|
protocol IntConvertible {
|
|
func toInt() -> Int // OK
|
|
}
|
|
|
|
* Even unlabeled parameter names should be meaningful as they'll be
|
|
referred to in comments and visible in "generated headers"
|
|
(cmd-click in Xcode):
|
|
|
|
.. parsed-literal::
|
|
|
|
/// Reserve enough space to store \`\ **minimumCapacity**\ \` elements.
|
|
///
|
|
/// PostCondition: \`\ capacity >= **minimumCapacity**\ \` and the array has
|
|
/// mutable contiguous storage.
|
|
///
|
|
/// Complexity: O(\`count\`)
|
|
mutating func reserveCapacity(_ **minimumCapacity**: Int)
|
|
|
|
* Type parameter names of generic types describe the role of the
|
|
parameter, e.g.
|
|
|
|
.. parsed-literal::
|
|
|
|
struct Dictionary<**Key**, **Value**> { // *not* Dictionary<**K**, **V**>
|
|
|
|
Acceptable Short or Non-Descriptive Names
|
|
-----------------------------------------
|
|
|
|
* Type parameter names of generic functions may be single characters:
|
|
|
|
.. parsed-literal::
|
|
|
|
func swap<**T**>(lhs: inout T, rhs: inout T)
|
|
|
|
* `lhs` and `rhs` are acceptable names for binary operator or
|
|
symmetric binary function parameters:
|
|
|
|
.. parsed-literal::
|
|
|
|
func + (**lhs**: Int, **rhs**: Int) -> Int
|
|
|
|
func swap<T>(**lhs**: inout T, **rhs**: inout T)
|
|
|
|
* `body` is an acceptable name for a trailing closure argument when
|
|
the resulting construct is supposed to act like a language extension
|
|
and is likely to have side-effects::
|
|
|
|
func map<U>(_ transformation: T->U) -> [U] // not this one
|
|
|
|
func forEach<S: SequenceType>(_ body: (S.Iterator.Element) -> ())
|
|
|
|
Prefixes and Suffixes
|
|
---------------------
|
|
|
|
* `Any` is used as a prefix to denote "type erasure,"
|
|
e.g. `AnySequence<T>` wraps any sequence with element type `T`,
|
|
conforms to `SequenceType` itself, and forwards all operations to the
|
|
wrapped sequence. When handling the wrapper, the specific type of
|
|
the wrapped sequence is fully hidden.
|
|
|
|
* `Custom` is used as a prefix for special protocols that will always
|
|
be dynamically checked for at runtime and don't make good generic
|
|
constraints, e.g. `CustomStringConvertible`.
|
|
|
|
* `InPlace` is used as a suffix to denote the mutating member of a
|
|
pair of related methods:
|
|
|
|
.. parsed-literal::
|
|
|
|
extension Set {
|
|
func union(_ other: Set) -> Set
|
|
mutating func union\ **InPlace**\ (_ other: Set)
|
|
}
|
|
|
|
* `with` is used as a prefix to denote a function that executes a
|
|
closure within a context, such as a guaranteed lifetime:
|
|
|
|
.. parsed-literal::
|
|
|
|
s.\ **with**\ CString {
|
|
let fd = fopen($0)
|
|
...
|
|
} // don't use that pointer after the closing brace
|
|
|
|
* `Pointer` is used as a suffix to denote a non-class type that acts
|
|
like a reference, c.f. `ManagedBufferPointer`
|
|
|
|
* `unsafe` or `Unsafe` is *always* used as a prefix when a function or
|
|
type allows the user to violate memory or type safety, except on
|
|
methods of types whose names begin with `Unsafe`, where the type
|
|
name is assumed to convey that.
|
|
|
|
* `C` is used as a prefix to denote types corresponding to C language
|
|
types, e.g. `CChar`.
|