11:42 AM
議論がとっ散らかるとよくないのでサブタイプが存在することによって発生する大きな問題点を2つ、整理します。
11:45 AM
まず1つ目がサブタイプであるにも関わらず、実体が異なってしまうという点 var s = 1 var a: Int = s var b: Int? = s のaとbが異なるということですね。クラスサブクラス、あるいはExistentialと具体型の関係なら、これは同じものを指すわけです。(Existentialは厳密には異なるが省略) var s = Cat() var a: Animal = s var b: Cat = s この結果発生する問題として、 実態が異なっているということを知っているユーザーと知らないユーザーとの間で、期待する挙動に差が出てきます。例えば
11:46 AM
https://discord.com/channels/291054398077927425/375206337937801216/806433474579005440 最近発生したバグとされるこの挙動。 AnyHashableにInt?の値を入れた時に、Intを入れた時と異なってしまう、というバグ
11:46 AM
でもこれは、「いやいやそうは言っても .some(1)1 は別でしょ」っていう理解のユーザーからは、AnyHashableの値が異なることこそが期待される挙動なはずです。
11:48 AM
このOptionalであるか否かが同一かどうかというのは、文脈によっても期待される挙動が異なるので、ケースバイケースでコンパイラの挙動が変わることが期待されてしまう。
11:48 AM
片方を立てれば片方は立たなくなる、という問題の根源になりえるわけです。
11:48 AM
次 2つ目、サブタイプのルールづけに優先順位が必要という話。
11:51 AM
これは結構私は方々でぶーを垂れてるので知ってるかもですが、 TがT?のサブタイプである UがTのサブタイプであるならばU?はT?のサブタイプである この2点がSwiftでは許可されています。で、下のコードはコンパイルが通る。 var s = Cat() var a: Animal = s // CatとAnimalのサブタイプ関係が成り立つことを示す var b: Cat? = s var c: Animal? = b U?はT?のサブタイプ、は具体のコードとしては、 UITableViewController? な変数が UIViewController? に渡せる、というのが頻出すると思います。 (edited)
11:52 AM
もちろんOptionalは実体は別なので、暗黙的な変換が挟まるわけですが、どうなっているかというと
11:53 AM
var s = Cat() var a: Animal = s // CatとAnimalのサブタイプ関係が成り立つことを示す var b: Cat? = .some(s) var c: Animal? = b.map { $0 as Animal } mapのところは本当は違うと思うんですが、まあ雑にこんな感じ。 (edited)
11:54 AM
じゃあここに一行付け加えて、これはどうあるべきでしょうか。というのが問題になります。 var d: Cat?? = b // b: Cat?
11:55 AM
解釈としては2通りあって、 1. オプショナルのサブタイプなので.someでラップする 2. CatはCat?のサブタイプなのだから、.mapでOK
11:57 AM
今このコードだと、Cat?は.someなので結果は同じなんですが、Cat?が.noneだと、1,2のどちらを採用するかで結果が変わります。
11:58 AM
// 1. var d1 = .some(b) // 見たまま.some(.none)になります // 2. var d2 = b.map { $0 as Cat? } // これは.noneになります じゃあこれがどういう問題を引き起こしたかというと
11:59 AM
過去のSwiftではコンテキストの差によって2.の変換が採用されていた時代がありました。
12:01 PM