Swift Digest
SE-0133 | Swift Evolution

Rename flatten() to joined()

Proposal
SE-0133
Authors
Jacob Bandes-Storch
Review Manager
Chris Lattner
Status
Implemented (Swift 3.0)

01 何が問題だったのか

Swift 3 以前の標準ライブラリには、シーケンスを連結する似たような API が 2 つ存在していました。要素同士の間に区切りを挟んで連結する joined(separator:) と、区切りなしでそのままフラットにする flatten() です。

extension Sequence where Iterator.Element : Sequence {
  public func joined<Separator: Sequence>(separator: Separator) -> JoinedSequence<Self>
  public func flatten() -> FlattenSequence<Self>
}

利用者から見ると、「区切りなしで連結すること」と「フラットにすること」は同じ操作であり、別名の API として分かれている必要はありません。名前が分かれていることで、どちらを使うべきか迷ったり、空の区切りを渡したい場面でわざわざ flatten() を思い出す必要があったりと、API の見通しが悪くなっていました。

さらに、String のシーケンスを結合するための joined(separator:) には区切りなしで連結する手段が用意されておらず、空文字列を明示的に渡す必要がありました。

["ab", "d"].joined(separator: "")  // "abd" と書く必要があった

02 どのように解決されるのか

flatten() を廃止し、引数なしの joined() に統合します。これにより、区切りの有無にかかわらず同じ名前で連結を表現できるようになります。

[[1, 2], [3]].joined()                // [1, 2, 3]    (従来の flatten() に相当)
[[1, 2], [3]].joined(separator: [])   // [1, 2, 3]
[[1, 2], [3]].joined(separator: [0])  // [1, 2, 0, 3]

あわせて、String のシーケンスに対する joined(separator:) では separator のデフォルト値が "" になり、引数なしで呼び出せるようになります。

extension Sequence where Iterator.Element == String {
  func joined(separator: String = "") -> String { ... }
}

["ab", "d"].joined()               // "abd"
["ab", "d"].joined(separator: "")  // "abd"
["ab", "d"].joined(separator: "_") // "ab_d"

既存の flatten() を使っているコードは joined() への書き換えが必要ですが、移行は機械的に行えます。実行時の挙動は変わりません。