こちらのプロポーサルを検証してまとめました。
非推奨になったメソッド
Swift4.1から以下のflatMap(_:)メソッドが非推奨となりました。
func flatMap<U>(_:(Element) -> U?) -> [U]
あわせてこちらも非推奨になった。
func flatMap(_: (Element) -> String?) -> [String]
追加されたメソッド
代わりに以下のメソッドが追加されました。
func compactMap<U>(_ transform: (Element) throws -> U?) rethrows -> [U]
よく見ると、どうやらメソッド名がリネームされただけのようです。
どうしてわざわざリネームしたのでしょうか?
動機
上記の非推奨にされたflatMap(:_)メソッドは、以下のように配列の値を変更しつつ、フィルタリングも行いたい時に使用されていた方が多いかと思います。
(mapはフィルタリングできないし、filterは型の変換が行えない。ところがこいつは両方行える。)
10> "H1e2l3l4o5Wo7l8d".flatMap { Int.init(String($0)) }
$R9: [Int] = 7 values {
[0] = 1
[1] = 2
[2] = 3
[3] = 4
[4] = 5
[5] = 7
[6] = 8
}
上記、 Int.init
の結果が失敗した場合、nilが返され、その値は出力される配列から除外されます。
しかしながら、本来のflatMap(_:)メソッドは、Haskellのリストモナドが由来となっており、今回その由来元のメソッドは無事に残されております。
今回残ったflatMap(_:)メソッド
Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element] where S: Sequence
上記のメソッドの役割は、リストモナドで検索をかけていただけたらと思います。
ではなぜその他の2つのflatMap(_:)メソッドを非推奨にして、代わりにあらたにリネームしただけの関数を追加したかと言うと以下の問題がswift4で発生するようになったためです。
swift4から String が Sequence となった。
従って、以下names1とnames2は、同様の結果を返すように見えますが、異なる結果が返る用になりました。
struct Person {
var name: String
init(_ name: String) { self.name = name }
}
func getNames(_ people: [Person]) -> [String] {
return people.flatMap { $0.name }
}
let people = [Person("tanaka"), Person("yoshida")]
let names1 = getNames(people)
print("names1: \(names1)")
let names2 = people.flatMap { $0.name }
print("names2: \(names2)")
names1: ["tanaka", "yoshida"]
names2: ["tanaka", "yoshida"]
names1: ["tanaka", "yoshida"]
names2: ["t", "a", "n", "a", "k", "a", "y",”o” "s", "h", "i", "d", "a"]
Swift4以前は、StringはSequeceではなかったため、
どちらもCollection側の flatMap(_:) メソッドが使用されたのに対し、Swift4.0の方では、 names1 が非推奨にされたCollection側の flatMap(_:) メソッドが使われ、 names2 は、 今回残った本来の flatMap(_:) メソッドが使用されたためです。
結論
とういこともあり、今回非推奨にした flatMap(_:) メソッドは本来のリストモナドのための flatMap(_:) メソッドと名前がかぶっておかしいし、Swift4からStringがSequenceになって更に上記のメソッドとぶつかってしまい、紛らわしいしということもあり、 compactMap(_:) へとリネームされてしまいました。
参照
swift-evolution/0187-introduce-filtermap.md at master · apple/swift-evolution
Introduce Sequence.compactMap(_:)
flatMap(_:) - Sequence | Apple Developer Documentation
func flatMap(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
flatMap(_:) - Sequence | Apple Developer Documentation
func flatMap(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
flatMap(_:) - Array | Apple Developer Documentation
func flatMap(_ transform: (Element) throws -> String?) rethrows -> [String]