Edited at

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

More than 3 years have passed since last update.


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:

    明白なselfがいないとき

    min(x, y, z)
    



  2. When the function is an unconstrained generic:

    関数が制約なく汎用的なとき

    print(x)
    



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

    関数の構文が確立されたドメイン表記の一部のとき

    sin(x)
    






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

    型、protocol、enumはUpperCamelCase、それ以外は、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:

    また、形(Shape)と、集合(Collection)は異なるドメインですので、同じプログラム内で以下の書き方も問題ありません。

    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:

    しかし、以下のindexメソッドは異なる意味なので、異なる名前であるべきです。

    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:

    デフォルト引数は一般的にメソッドファミリに使用されることを好まれます。

    なぜなら、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

      メソッドや関数の、はじめのパラメータは、requiredな引数ラベルを持つべきではありません。





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

      メソッドや関数の、2番目移行のパラメータは、requiredな引数ラベルを持つべきです。





    • All parameters to initializers should have required argument labels.

      イニシャライザの全てのパラメータは、requiredな引数ラベルを持つべきです。







  • 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)
    }
    doc1.close()
    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って何?



関連