Skip to content

Instantly share code, notes, and snippets.

@matarillo
Last active August 29, 2015 14:14
Show Gist options
  • Select an option

  • Save matarillo/84322cfca7fffe22720f to your computer and use it in GitHub Desktop.

Select an option

Save matarillo/84322cfca7fffe22720f to your computer and use it in GitHub Desktop.
C#のジェネリクス メモ

C#のジェネリクス メモ

Javaとの違い

まずはさらっと。型消去の話は深堀りして、変性の話は簡単に? 変性とワイルドカードも掘り下げるなら、ちょっと考えてみます。

  • ランタイム側がフルサポート(Javaは型消去)
  • 値型サポート(実行時に特殊化されたコードを生成するのでボックス化なし)
  • 配列は暗黙的にジェネリックコレクションインターフェースを実装
  • 定義側の変性(ワイルドカードによる利用側の変性と比べて向き不向きがある)

型消去だとどういうときにしんどいか

型パラメータTの実引数が欲しいというのは、まあ言ってしまえばリフレクションしたいです、ってことなんだけど、リフレクションはどこまで黒魔術なのか、という。

まずは new制約の話

  • new T() できない
  • それは型制約の問題では説
  • O/RマッパーやJSONデシリアライズなど、ライブラリでつらい
  • Foo.class渡してもらえばいいだろ
  • ところが、プロパティ(getterでもパブリックフィールドでもいいけど)の型がList<Bar>とかだったりするとそのBarが消えてたりして泣くってほんとう?
  • Javaの人はそういう時、 List<Bar> は使わずに BarList を作るの?
  • ファクトリが必要だね説
  • つまりそういうことで、POJOだけでこぐのがしんどくならないか。

nagiseさんからは new制約以外で何かないか、というリクエストもあるので、すこし考えてみる

  • C# だと、基本的には静的だし最適化も効かせるんだけど、ちょびっと動的にしたい、たとえば初回はリフレクションで、以降はなるべく最適化されたコードを実行するとか。→実コード例が必要なら当日までに用意
  • あと型パラメータの実引数によって処理を変えたいときがあったりして、型制約だけ異なるオーバーロードはできないし、別メソッドにしてしまってもいいけどなんだかな……ってなときにこっそり型を見たい。→実コード例が必要なら当日までに用意

つっこんだ話

  • Javaは全体的に「継承でやれ」が多くて、それは型階層を全部コントロールできるアプリケーションのレイヤーではまあいいんだけど、ライブラリは型階層に制約をつけられない、つけたくないケースがある。→フレームワークならOKか、みたいな話は懇親会行き
  • ジェネリクス(パラメータ多相)って、継承(部分型多相)と比べると本来はそういうところにメリットがあるような気がするが、どうなんでしょうね→変な話題に踏み込みすぎかも。でも下の型制約にちょっと絡むんだよね
  • あと、Javaも値型サポートに動いてるけど、値型サポートすると型消去ではしんどそう。→それともC++のテンプレートみたいにコンパイル時に特殊化するのかしら、いやーそれこそありえなさげ

型制約

ちょっとだけしゃべる

  • Javaとはほとんど違いがない
  • 静的メソッドがけっこう鬼門
  • このあたりも、上で書いた「パラメータ多相と部分型多相」みたいな話で。F# だと構造的部分型な型制約ができるからさらに継承の必要性が下がると理解している
  • Scalaは静的メソッドを排したとか型クラスエミュレートしてるとか、みたいな話は懇親会行き

C#/Javaの型制約は、継承をベースにしているので、インスタンスメソッドは呼べますが、静的メソッドは呼べません。C#のジェネリクスで、演算子が使えなくてイライラした人も多いのではないでしょうか?(C#のジェネリクスが値型も対象にできるのはいいことなんですが、算術演算に悩んだりとか、ありますよね。)

http://d.hatena.ne.jp/matarillo/20141010/p1

高階型引数(高カインド型?)

セッションじゃやらない気がする

  • C# ではできません(というか、ドトネトにその機構がない)
  • JavaでもできないけどScalaでは型消去+アノテーションで対応?よくしらない
  • C#の基本方針として、ランタイムがサポートしてないことは原則やらない、というのは、要は言語間相互運用性をかなり重視してて、たとえばVB.NETで作ったライブラリ(dll)を呼び出したり逆に呼びだされたり、というときに、実行時例外がスローされたり、あるいはC# だけがサポートしている制約が無視されたり、みたいなことを避けようとしていると思われる。
  • IL向けのC言語、みたいな感じの立ち位置?

再帰ジェネリクス(nagiseさんが記事書いてたあれ)

セッションじゃやらない気がする

  • ふつうの、継承をベースとした型制約だと基底型を扱うかっこう
  • 再帰ジェネリクス&継承で、派生型を扱えるケースがある
  • これはハックだなあ
@bleis-tift
Copy link
Copy Markdown

変位指定の話はしないんですか?
Javaの変位指定とC#の変位指定は方針が違うので、そのあたりの話もあると面白いと思います。
F#はその点、C#の変位指定を退化させ、オブジェクト指向的な型階層とは一定の距離を置いている感じですが。
ただ、変位指定の話をするならやはりScalaは強いし欲しい気がしてううむ。

@matarillo
Copy link
Copy Markdown
Author

上のメモには冒頭にちょっとしか書いてませんが、ふくらますかどうか、nagiseさんと相談してみます!

@matarillo
Copy link
Copy Markdown
Author

変位指定の話はこれをベースにするのでいいかなあ
https://gist.github.com/matarillo/92c076d3c6cd972d4b09

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment