Avatar
omochimetaru 3/8/2019 3:41 AM
Selfであってもcontravariant positionになっていないならば許すのね。
3:42 AM
initはSelfを返してるようなもんだから、covariantだから、セーフかね
3:43 AM
protocol P { init(name: String) func a() -> Self } struct S : P { init(name: String) {} func a() -> S { fatalError() } } func takeExistentialArg(_ p: P) {}
3:43 AM
なるほどね
3:44 AM
protocol P { init(name: String) func a() -> Self } protocol Q { func takeSelf(_ self_: Self) } func takeExistentialArgP(_ p: P) {} // Protocol 'Q' can only be used as a generic constraint because it has Self or associated type requirements func takeExistentialArgQ(_ q: Q) {}
3:44 AM
このエラーメッセージ、「it has Self」のところ、「it has contravariant Self」のほうが、良さそう。
3:46 AM
protocol P { init(name: String) func a() -> Self } protocol Q { func takeSelf(_ self_: Self) } extension P { func takeSelf(_ self_: Self) { } } func takeExistentialArgP(_ p: P) {}
3:46 AM
However, nowadays we also have protocol extensions, so even if a protocol doesn't have any core requirements with contravariant Self or associated type arguments, contravariant protocol methods can be added by extensions, so the type system issues unavoidably exist already.
3:47 AM
たとえ、protocol Pの本体が、contravariant Selfを使っていないとしても、extensionでそれを追加する事ができちゃうので、すでに一部壊れてる
3:50 AM
extension P { func transfer(_ self_: Self) -> Self { return self_ } } func takeExistentialArgP(_ p: P) { // Member 'transfer' cannot be used on value of protocol type 'P'; use a generic constraint instead let a = p.transfer(p) }
3:50 AM
ウオオ
3:51 AM
protocol Pに生やしたのに existential Pでは使用禁止になるケースあるのか。
3:53 AM
これがまさに
We'd follow the existing rule which is that protocol members that use contravariant Self or associated types aren't available on the existential.
3:54 AM
だから、contra Self or assoctypeなメンバーの使用はできないという制限(これは実は既存)のもとで contra Self or assoctypeな protocolでもexistentialを可能にしよう っていう提案か。 (edited)
3:56 AM
これって要するに、
3:56 AM
protocolからcontra Selfとassoctypeを取り除いた親protocolを作って、親protocolのexistentialを使う、っていう現時点で可能なワークアラウンドと、表現能力は一緒かな (edited)
3:59 AM
existential P が protocol P に準拠できないのもこの差分があるから、って言うこともできるんかな
4:00 AM
つまり、existential Pは <T: P> と違って真の型を失ったただの型境界にすぎない?
4:03 AM
func foo<T: P>(_: T) extension P { func _forwardToFoo() { foo(self) } } func callFooOnEach(_ ps: [P]) { for p in ps { p._forwardToFoo() } }
4:04 AM
you can in fact "open" the existential by invoking a protocol extension method, which will give you Self as the dynamic type of the value inside the method, which you can then pass to generic functions:
4:04 AM
protocol extension経由でSelfをreopenできるってこれなんか前話したな
4:05 AM
Pの中に隠れてるから _forwardToFoo を呼ぶ側からみるとセーフなのか。