Swift Digest
SE-0060 | Swift Evolution

Enforcing order of defaulted parameters

Proposal
SE-0060
Authors
Joe Groff
Review Manager
Chris Lattner
Status
Implemented (Swift 3.0)

01 何が問題だったのか

Swift は Smalltalk や Objective-C の系譜を汲み、引数ラベルを順序に意味のあるメソッド名の一部として扱う言語です。ところが デフォルト値を持つ引数に限っては例外 があり、呼び出し側で宣言順を無視して自由に並べ替えることができました。

func defaultArguments(a: Int = 0, b: Int = 0, c: Int = 0) {}

defaultArguments(a: 0, b: 1, c: 2) // OK
defaultArguments(b: 0, a: 1, c: 2) // これも通ってしまう

この挙動は、Swift がリリース前に備えていた Python ライクな「キーワード引数の自由な並べ替え」機能の名残です。その後 Swift は Cocoa フレームワークの影響を受け、引数ラベルと順序を API 設計の一部として重視する方向に進みました。同じ API の呼び出しがどのコードベースでも同じように読めることは、読みやすさと予測可能性の両面で重要です。

しかし、デフォルト引数に限っては並べ替えが許されていたため、次のような問題が残っていました。

  • 存在が知られていない: そもそもこの機能に気付いていない利用者が多く、「便利だから使う」という形で機能していませんでした。
  • 驚きや拒否反応を招く: 知ったときに不自然だと感じる利用者もおり、言語の一貫性を損ねるコーナーケースとして認識されていました。
  • 言語仕様を複雑にする: 呼び出し順序のルールが引数のデフォルト有無で変わるため、仕様にも実装にも余計な場合分けを持ち込んでいました。

得られる利便性に対して、言語の一貫性を損なうデメリットのほうが大きくなっていた、というのがこの提案の出発点です。

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

呼び出し側で渡す引数は、デフォルト値の有無に関係なく常に宣言順に並べる よう統一されました。Swift 3.0 で実装されています。

宣言順の強制

デフォルト値を持たない引数と同じく、デフォルト値を持つ引数についても並べ替えはエラーになります。

func requiredArguments(a: Int, b: Int, c: Int) {}
func defaultArguments(a: Int = 0, b: Int = 0, c: Int = 0) {}

requiredArguments(a: 0, b: 1, c: 2)
requiredArguments(b: 0, a: 1, c: 2) // error

defaultArguments(a: 0, b: 1, c: 2)
defaultArguments(b: 0, a: 1, c: 2) // error

デフォルト引数の省略は従来どおり

デフォルト値を持つ引数は、これまでどおり任意に省略できます。ただし、明示的に渡す引数は宣言順に並んでいる必要があります。

defaultArguments(a: 0)       // OK
defaultArguments(b: 1)       // OK
defaultArguments(c: 2)       // OK
defaultArguments(a: 1, c: 2) // OK(b を省略、a と c は宣言順)
defaultArguments(b: 1, c: 2) // OK(a を省略、b と c は宣言順)
defaultArguments(c: 1, b: 2) // error(c と b が宣言順に反している)

「省略できる」と「並べ替えできる」は別の話で、省略は引き続き自由、並べ替えは不可 というのが新しいルールです。

既存コードへの影響

引数の並べ替えに頼っていた呼び出しは、宣言順に書き直す必要があります。ただし機械的な書き換えで済む変更のため、マイグレータで自動的に対応できます。