今回は SE-0014: AnySequence.init に制約を与える です。Swift のシーケンスの実装を理解していないのでだいぶ怪しいです...
ツッコミお待ちしています。
原文に従ってこの訳は Apache License 2.0 とします。
SE-0014: AnySequence.init に制約を与える
- 提案: SE-0014
- 著者: Max Moiseev
- ステータス: Swift 2.2 に向けて受理された (Bug)
- レビューマネージャ: Doug Gregor
はじめに
AnySequence
がその子孫にあたる型に呼び出しをデリゲートできるよう、イニシャライザは追加の制約を持つべきです。
動機
現在のところ AnySequence
は SequenceType
プロトコルのメソッドに対する呼び出しをその子孫にあたる型を持つシーケンスにデリゲートしません。この結果、必要に応じてその場で動的にダウンキャストすることになります(SequenceType.dropFirst
または SequenceType.prefix
のデフォルトの実装を見てください)。さらに、こちらの方がより重要ですが、デリゲーション無しでは SequenceType
のメソッドをカスタマイズした実装は無視されてしまうでしょう。
提案手法
このプルリクエストにある実装を見てください。
この種のデリゲーションを実現するには _SequenceBox
はもとのシーケンスだけではなく SubSequence
も 'ラップ' する必要があります。するとこのような宣言は:
internal class _SequenceBox<S : SequenceType>
: _AnySequenceBox<S.Generator.Element> { ... }
このようになるでしょう:
internal class _SequenceBox<
S : SequenceType
where
S.SubSequence : SequenceType,
S.SubSequence.Generator.Element == S.Generator.Element,
S.SubSequence.SubSequence == S.SubSequence
> : _AnySequenceBox<S.Generator.Element> { ... }
次に AnySequence.init
には以下のような制約がつくことになるでしょう。
変更前:
public struct AnySequence<Element> : SequenceType {
public init<
S: SequenceType
where
S.Generator.Element == Element
>(_ base: S) { ... }
}
変更後:
public struct AnySequence<Element> : SequenceType {
public init<
S: SequenceType
where
S.Generator.Element == Element,
S.SubSequence : SequenceType,
S.SubSequence.Generator.Element == Element,
S.SubSequence.SubSequence == S.SubSequence
>(_ base: S) { ... }
}
私たちは全ての SequenceType
の実装がこれらの制約を最初から満たしていてほしいと思います。するとこれらの制約は実際のところ SequenceType
プロトコル自体に適用されるべきなのです(現在のところそれは不可能なのですが)。技術的には S.SubSequence.SubSequence == S.SubSequence
は必ずしも必要ではないという点は触れておく価値があります。これは同じ型を要素に持つシーケンスは全てこの制約を満たしているからです。しかし現在のところそれを表現する方法はありません。
既存のコードに対する影響
全ての SequenceType
プロトコルに準拠する組み込み型は基本的に (SubSequence.SubSequence == SubSequence
) という関係を持つように作られるので、新しい制約が影響を与えることはありません。サードパーティーのコレクションも、もしデフォルトの SubSequence
(例えば Slice
)を使っていたとしても問題ないはずです。カスタムの SubSequence
を持つ型はそのプロトコルに準拠しなくなるかもしれません。