またSwiftでわからないことが [Swiftプログラミング]
昔Objective-Cで書いたアプリをSwiftに書き直しながらSwiftの勉強をしょぼしょぼ続けている。でも単に逐語的に変換したのではSwiftの勉強にはならないので、Swiftらしい言い回しになるように考えながらやってる。CodeWarriorのC++からObjective-Cに切り替えるときもそうやって苦労した。そんなことしてると全然進まない。慌てることはないとは言うものの、仕事でもmacOSに書くことがある(というかソフトウェアで解決しないといけないことはよくあってそのときは僕にはmacOSしかない)ので、いつまでもObjective-Cというわけにはいかない。悩ましい。
古いのを書き直してる中でまたよくわからないことに出くわした....
昔、厳密な光線追跡をObjective-Cで書いた。光線や媒質やその境界面の形状をオブジェクトで表して、光線オブジェクトが自分自身に光線セグメントを追加する形で光線追跡を実行するように書いた。それをSwiftに書き直している。
そのままでは面白くないので、今度はprotocolを使ってなるべく抽象的な表現をもとにして、それを具体化するように考えた。つまり境界面は光線を屈折や反射させるというprotocolに従うなにものか、媒質は光線に光路長を追加するなにものか、光線は波長と始点と進行方向を持つなにものか、と言うふうにして、個別の面形状や分散を持つ媒質はそれらのprotocolに従う構造体として書いてみようと考えた。
光線も最も単純な追跡をするだけのものから、位相や偏光なんかの属性を持ったものまで考えるけど、すべて媒質を経ると次の始点を追加して、境界面を経ると次の進行方向を追加するというprotocolに従うものとして共通化した。さらに光軸が定義されていて光線セグメントが光軸と同一平面内にあれば2次元の追跡を実行するようにも書こうと思った。そして位置や向きを表すベクトルも追跡が簡単になるように新しく定義しようと思った。そうする中でよくわからないことに出くわした。
問題を抜き出して書いてみる。例えば3次元ベクトルをこんなふうに書く。
もちろんこれでは何の役にも立たないけど、この場合は問題は発生しない。そしてこれを汎用にするために要素の型を指定できるようにジェネリックに書いたとする。こんな感じに。
でもこういうのって計算機科学的に深遠な問題があったりするので、突っ込むとキリがなかったりするので注意も必要ではある。
もちろんこれが解決しないと何も書けない、というわけではないのでスルーしていいようなものだけど、気にはなる。というか、不思議だ。
ジェネリック型による汎用化はC++なんかでもある(というかC++のほうではずっと出番が多い気がする)けど、他言語でもこういう制限てあるんだろうか。
古いのを書き直してる中でまたよくわからないことに出くわした....
昔、厳密な光線追跡をObjective-Cで書いた。光線や媒質やその境界面の形状をオブジェクトで表して、光線オブジェクトが自分自身に光線セグメントを追加する形で光線追跡を実行するように書いた。それをSwiftに書き直している。
そのままでは面白くないので、今度はprotocolを使ってなるべく抽象的な表現をもとにして、それを具体化するように考えた。つまり境界面は光線を屈折や反射させるというprotocolに従うなにものか、媒質は光線に光路長を追加するなにものか、光線は波長と始点と進行方向を持つなにものか、と言うふうにして、個別の面形状や分散を持つ媒質はそれらのprotocolに従う構造体として書いてみようと考えた。
光線も最も単純な追跡をするだけのものから、位相や偏光なんかの属性を持ったものまで考えるけど、すべて媒質を経ると次の始点を追加して、境界面を経ると次の進行方向を追加するというprotocolに従うものとして共通化した。さらに光軸が定義されていて光線セグメントが光軸と同一平面内にあれば2次元の追跡を実行するようにも書こうと思った。そして位置や向きを表すベクトルも追跡が簡単になるように新しく定義しようと思った。そうする中でよくわからないことに出くわした。
問題を抜き出して書いてみる。例えば3次元ベクトルをこんなふうに書く。
struct Vector { static let dimension = 3 // (1) var x: Double var y: Double var z: Double init? (components c: [Double]) { if (Vector.dimension != c.count) { // (2) return nil } self.x = c[0] self.y = c[1] self.z = c[2] } }3つの成分を持って浮動小数点数の配列で初期化できるようなものとして書いたとする。2次元ベクトルと同じprotocol(ここには関係ないので書いてない)に従うように書くために静的な定数dimensionを持っていて、その値と初期化での配列の長さが一致したときだけ初期化可能だとしてる。
もちろんこれでは何の役にも立たないけど、この場合は問題は発生しない。そしてこれを汎用にするために要素の型を指定できるようにジェネリックに書いたとする。こんな感じに。
struct GVector<T: Numeric> { static let dimension = 3 // (3) var x: T var y: T var z: Tところがこれは(3)のstaticな定数定義のところでコンパイルエラーが出る。
Swift Compiler Error: Static stored properties not supported in generic typesジェネリックな型を持つ構造体ではStatic stored properties(静的な格納プロパティ)はサポートされないとある。これを例えば
static var dimension: Int { // (4) return 3 }と計算型にするとエラーはない。なんでだろう。静的な格納プロパティは構造体それぞれではなく、ヒープのどこかにひとつだけ存在していてコンパイラがその場所を知っていればいいだけだと思うので、ジェネリックだろうがなんだろうか関係ないような気がする。それを(4)のように計算型にしたからと言ってコンパイラにとってなにが違うというんだろう。全然わからん。
でもこういうのって計算機科学的に深遠な問題があったりするので、突っ込むとキリがなかったりするので注意も必要ではある。
もちろんこれが解決しないと何も書けない、というわけではないのでスルーしていいようなものだけど、気にはなる。というか、不思議だ。
ジェネリック型による汎用化はC++なんかでもある(というかC++のほうではずっと出番が多い気がする)けど、他言語でもこういう制限てあるんだろうか。
2019-05-04 23:18
nice!(0)
コメント(0)
コメント 0