blob: 6c9cdb92335e2557d17df1c0efb4d976d8c74b25 [file] [log] [blame]
: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`.