More than 5 years have passed since last update.

Swift API Design Guidelinesを翻訳してみた(Conventions)

Last updated at Posted at 2015-12-25

Swift API Design Guidelinesを翻訳してみた(Conventions)

Conventions - 規約

General Conventions - 一般的な規約

  • Document the complexity of any computed property that is not O(1). People often assume that property access involves no significant computation, because they have stored properties as a mental model. Be sure to alert them when that assumption may be violated.

    計算量がO(1)で無いcomputed propetyには、複雑度をコメントに記述してください。 我々は、プロパティアクセスは大量の計算を伴わないとしばしば想定します。 なぜなら、普通プロパティといえば計算をともなわないstored propertyを想定するからです。 その想定に反するかもしれない場合は、必ず警告するようにしてください。

  • Prefer methods and properties to free functions. Free functions are used only in special cases:

    free functionでは無く、メソッドとプロパティを用いましょう。 free functionは、特別な場合にのみ使用されます。

  1. When there’s no obvious self:


    min(x, y, z)
  2. When the function is an unconstrained generic:


  3. When function syntax is part of the established domain notation:



  • Follow case conventions: names of types, protocols and enum cases are UpperCamelCase. Everything else is lowerCamelCase.


  • Methods can share a base name when they share the same basic meaning but operate on different types, or are in different domains.


  • For example, the following is encouraged, since the methods do essentially the same things:


    extension Shape { 
    /// Returns `true` iff `other` is within the area of `self`. 
    func contains(other: Point) -> Bool { ... }  
    /// Returns `true` iff `other` is entirely within the area of `self`. 
    func contains(other: Shape) -> Bool { ... }  
    /// Returns `true` iff `other` is within the area of `self`. 
    func contains(other: LineSegment) -> Bool { ... } 

  • And since geometric types and collections are separate domains, this is also fine in the same program:


    extension Collection where Element : Equatable { 
    /// Returns `true` iff `self` contains an element equal to 
    /// `sought`. func contains(sought: Element) -> Bool { ... } 

  • However, these index methods have different semantics, and should have been named differently:


    extension Database { 
    /// Rebuilds the database's search index 
    func index() { ... }  
    /// Returns the `n`th row in the given table. 
    func index(n: Int, inTable: TableID) -> TableRow { ... } 

  • Lastly, avoid “overloading on return type” because it causes ambiguities in the presence of type inference:


    extension Box { 
    /// Returns the `Int` stored in `self`, if any, and
    /// `nil` otherwise.
    func value() -> Int? { ... }
    /// Returns the `String` stored in `self`, if any, and 
    /// `nil` otherwise. 
    func value() -> String? { ... } 

Parameters - パラメータ

  • Take advantage of defaulted arguments when it simplifies common uses. Any parameter with a single commonly-used value is a candidate for defaulting.


  • Default arguments improve readability by hiding irrelevant information. For example,


    let order = lastName.compare( 
    royalFamilyName, options: [], range: nil, locale: nil)

  • can become the much simpler:


    let order = lastName.compare(royalFamilyName)

  • Default arguments are generally preferable to the use of method families, because they impose a lower cognitive burden on anyone trying to understand the API:

    (※訳注: メソッドファミリ init, initWith... や、copy, copyWith... などの引数が異なるが行う内容は同一の物)

    extension String { 
    /// *...description...* 
    public func compare( 
    other: String, options: CompareOptions = [], 
    range: Range? = nil, locale: Locale? = nil 
    ) -> Ordering 

  • The above may not be simple, but it is much simpler than:


    extension String { 
    /// *...description 1...* 
    public func compare(other: String) -> Ordering 
    /// *...description 2...* 
    public func compare(other: String, options: CompareOptions) -> Ordering 
    /// *...description 3...* 
    public func compare( other: String, options: CompareOptions, range: Range) -> Ordering 
    /// *...description 4...* 
    public func compare( other: String, options: StringCompareOptions, range: Range, locale: Locale) -> Ordering }

  • Every member of a method family needs to be separately documented and understood by users. To decide among them, a user needs to understand all of them, and occasional surprising relationships—for example, fooWithBar(nil) and foo() aren’t always synonyms—make this a tedious process of ferreting out minor differences in mostly-identical documentation. Using a single method with defaults provides a vastly superior programmer experience.

    ユーザは全てを理解する必要があります。また、時たま起こる驚くべき関連— 例えば、fooWithBar(nil) と foo() は必ずしも同義ではありません—この大部分は同一のドキュメントに若干の違いをferretingの退屈なプロセスにします。

  • Prefer to locate parameters with defaults towards the end of the parameter list. Parameters without defaults are usually more essential to the semantics of a method, and provide a stable initial pattern of use where methods are invoked.


  • Prefer to follow the language’s defaults for the presence of argument labels


  • In other words, usually:


    • First parameters to methods and functions should not have required argument labels


    • Other parameters to methods and functions should have required argument labels.


    • All parameters to initializers should have required argument labels.


  • The above corresponds to where the language would require argument labels if each parameter was declared with the form:


    identifier: Type

  • There are only a few exceptions:


    • In initializers that should be seen as “full-width type conversions,” the initial argument should be the source of the conversion, and should be unlabelled.

      型的に大きくなる型変換で見られるべきイニシャライザの場合、第一引数は 変換元であり、引数ラベルはつけるべきではありません。

    extension String { 
    //  `x`を基数(radix)を元に文字列に変換(BigInt → String) 
    init(_ x: BigInt, radix: Int = 10) // Note the initial separate underscore 
    text = "The value is: " 
    text += String(veryLargeNumber) 
    text += " and in hexadecimal, it's" 
    text += String(veryLargeNumber, radix: 16)

    • In “narrowing” type conversions, though, a label that describes the narrowing is recommended:


    extension UInt32 { 
    init(_ value: Int16) // 型的に大きくなる(Int16 → UInt32)のでラベルは不要 
    // 型的に小さくなる(UInt64 → UInt32)ので、切り捨てられる旨のラベルを推奨 
    init(truncating bits: UInt64) 
    init(saturating value: UInt64) 

    • When all parameters are peers that can’t be usefully distinguished, none should be labelled. Well-known examples include min(number1, number2) and zip(sequence1, sequence2).

      全てのパラメータが同等で有効に区別出来ない場合、引数ラベルはつけられるべきではありません。よく知られている例として、min(number1, number2zip(sequence1, sequence2)があります。

    extension Document { 
    func close(completionHandler completion: ((Bool) -> Void)? = nil)
    doc2.close(completionHandler: app.quit)

    • As you can see, this practice makes calls read correctly regardless of whether the argument is passed explicitly. If instead you omit the parameter description, the call may incorrectly imply the argument is the direct object of the “sentence:”


    extension Document { 
    func close(completion: ((Bool) -> Void)? = nil) 
    doc.close(app.quit) // 閉じながらやめる関数?

    • If you attach the parameter description to the function’s base name, it will “dangle” when the default is used:


    extension Document { 
    func closeWithCompletionHandler(completion: ((Bool) -> Void)? = nil) 
    doc.closeWithCompletionHandler() // CompletionHandlerって何?



Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up