Swift Digest
SE-0372 | Swift Evolution

ソートがstableであることを文書化する

Document Sorting as Stable

Proposal
SE-0372
Authors
Nate Cook
Review Manager
Tony Allevato
Status
Implemented (Swift 5.8)

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

01 何が問題だったのか

stable sort とは、比較結果が等しい(または順序付けできない)要素同士の相対順序を、ソート前と同じまま保つソートのことです。たとえば姓でソート済みのプレイヤー一覧を、今度は名でソートしても、同じ名のプレイヤーは元の姓の順序のまま残ります。

var roster = [
   Player(first: "Sam", last: "Coffey"),
   Player(first: "Ashley", last: "Hatch"),
   Player(first: "Kristie", last: "Mewis"),
   Player(first: "Ashley", last: "Sanchez"),
   Player(first: "Sophia", last: "Smith"),
]

roster.sort(by: { $0.first < $1.first })
// roster == [
//    Player(first: "Ashley", last: "Hatch"),
//    Player(first: "Ashley", last: "Sanchez"),
//    Player(first: "Kristie", last: "Mewis"),
//    Player(first: "Sam", last: "Coffey"),
//    Player(first: "Sophia", last: "Smith"),
// ]

整数の配列のように Comparable 適合だけでソートする場合、等しい要素は見分けが付かないので stability は観察できません。しかし、要素のプロパティの一部だけを使ってソートする場合には、stability の有無が結果に表れます。スプレッドシートで複数の列を順にソートして多段ソートを実現するような使い方は、stability を前提としています。

標準ライブラリの sort() は Swift 5 より前のタイミングで stable な実装に変更されていました。しかし、ドキュメント上は次のように「stable とは保証しない」と明記されたままでした。

The sorting algorithm is not guaranteed to be stable. A stable sort preserves the relative order of elements that compare as equal.

この状態は、stability を知っている開発者にとっては「実際には stable なのに頼ってよいか分からない」という不便さにつながり、stability を知らない開発者にとっては「将来 stable でなくなったら原因不明のバグを踏みかねない」というリスクにつながっていました。

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

標準ライブラリの sort / sorted が stable であることを、ドキュメント上も正式に保証します。現行の Swift ランタイムはすべて stable な実装を含んでいる(ABI stability より前に stable 化されている)ため、API やアルゴリズムの変更は不要で、ドキュメントのコメントを次のように書き換えるだけの変更です。

- /// The sorting algorithm is not guaranteed to be stable. A stable sort
+ /// The sorting algorithm is guaranteed to be stable. A stable sort
  /// preserves the relative order of elements that compare as equal.

これにより、比較結果が等しい要素の相対順序が保たれることを前提にコードを書けるようになります。複数のキーで順次ソートして多段ソートを表現するパターンも、言語仕様として安心して使えます。今後 sort のアルゴリズムに変更が入る場合も、stability を維持することが要件となります。

なお、stability を犠牲にする代わりに追加のメモリ確保を避けるといった別の特性を持つソート(unstableSort() のようなもの)を別途用意する案も検討されました。しかし、stability を欠くこと自体には利点がなく、別の特性を持つソート API が将来提案された際に、その API 側で命名やドキュメントを通じて stability の有無を明示すればよい、と整理されています。デフォルトの sort を stable と保証することの価値は変わらない、という結論です。

03 今後の見通し

ソート関連の改善としては、key path や関数ベースのソート API、ソート済みコレクション型/プロトコル、sort descriptor といった拡張も検討対象として挙げられています。いずれも今回のスコープ外で、今後のpitchやproposalで個別に議論されていく方向性として示されているにとどまり、実現が約束されているものではありません。