概要
え? 動的型付けは Python のことやろ? C# もできるんか? てかそれがジェネリック(どんな型でも引数にとれる)じゃないの? あれ? てか object
型は? やべ、ジェネリックと object
との違いがわからなくなってきた。
流し読みノート
object と dynamic の違い
- 動的型付けには
dynamic
型を使う。object
と同じでほぼすべてのものへの参照を保持可能。違うのは、object
でとった引数はobject
にないメソッドやプロパティを使えないけど、dynamic
ならなんでもやりたい放題なところだ。ええい、全然うまく書けん。以下に実例を記す。
// ↓これはコンパイル不可。
// object に Frobnicate なんてメソッドないからね。
public static object UseObjects(object a, object b)
{
a.Frobnicate();
return a + b;
}
// コンパイル可。
public static dynamic UseObjects(dynamic a, dynamic b)
{
a.Frobnicate(); // たとえば int が渡されてきたら
// 当然 Frobinicate メソッドはないので
// RuntimeBinderException 発生。
// うん、 Python と一緒だね。
return a + b;
}
- ……いや、コンパイル可はわかるけどいいとこないやん。 C# のいいとこ死んでるじゃん。まあ↓のような型を定義すればエラー起こらないようにできるけど……。
pulbic class Frobnicatable
{
public void Frobnicate() {}
pulbic static Frobnicatable operator +(Frobnicatable left, Frobnicatable right)
{
return new Frobnicatable();
}
}
// は? だったら dynamic で引数受けとらずに Frobnicatable でとればええやん。
- ちなみに frobnicate って言葉は知らなかったんだけど、「いじくる」みたいな意味らしいよ。いじくるってのは tweak をよく使うけれど、とくに IT 関連で、物理的なものをいじくるときに使うみたい。 Stop frobnicating that switch!(スイッチをいじんのをやめろ)
なんで dynamic なんか追加したんや
- Microsoft が
dynamic
を C# 4.0 から追加したのは、いくつかの相互運用のシナリオを単純にするため…… COM(Component Object Model)のサポートのためだ。- 何???
- COM は .NET が出る前に多言語間開発をサポートしてたもの。 .NET が出たから役目はなくなってた。ただ Windows8 からまた COM ベースの API が提供されはじめた。
- COM ベース API を扱う方法を COM オートメーションという。
- COM オートメーションの利用者として有名なのは VBA(Visual Basic for Applications)。
- なんかよくわからんけど、そのオートメーションとやらは動的な呼び出しに対応しているらしい。
- ほんでなんかよくわからんけど、動的な呼び出しってのは、足りない引数を自動で供給することらしい。もう全然わからん。
- 動的な言語では、これを自動で行うんだって。
- でも C# はそれをしないから、たとえば Microsoft Word の16個の引数を受け取る Open メソッドを開くとき、不要なのに、いちいち16個の値を書かないといけなかったそうな。不要な引数が省略できないってこと。ハア?
- で
dynamic
キーワードははるかに優雅にそれを処理するそうな。ヘエ……。 - まあそれでかじゃないようだけど、より優雅に、より洗練されたコードにするために導入されたものだってことよね。
- 「
dynamic
型はより自然に見えるコードを書けるように影で働くのです」「より自然な表現にできることと余計なものを減らすことが目的」。dynamic
の役割は COM と他の言語との相互運用の単純化であって、静的型付けのかわりに動的型付けプログラムを作ることではない。
最後だけ、ちょっとわかった。なにか、我々にはあんまり関係ないものを、隠れたところでキレイに処理するため機能なのだろう。 Python はシンプルな言語だけど、それは言語が裏で面倒なことを請け負ってくれているのだ。そういう類のハナシなのだろう。
なるほどねい。動的型付けである Python が型ヒントを取り入れたように、静的型付け言語も動的なものが欲しくなるときがあるってことかね。
dynamic は型であり型ではない
哲学かな?
- C# では
dynamic
型は特別な型として捉えられてるけれど、 CLR はdynamic
を型として認識してない。実行時にはobject
として扱う。- だから
List<dynamic>
は実際にはList<object>
になってる。
- だから
var x = new List<dynamic>();
Console.WriteLine(x.GetType() == typeof(List<object>)); // true になる。お前 object やないかい!
- だけどコンパイラが
dynamic
を認識しており、dynamic
の含まれる式にまつわる多くの決定を実行時まで遅らせるようなコードを生成してくれてる。コンパイラのおかげなんだねやっぱ。ついこないだも「インラインメソッドは結局コンパイラがフツーのメソッドに変換してくれてる」って話をしてたしな。 typeof(dynamic)
は対応するType
オブジェクトがないからコンパイルエラーになる。へえー。これぞうんちく。
小休憩
たしかに、これは動的型付けだ。我々 Pythonista が慣れ親しんでいるものだ。だけど C# コードで目にすると、ただ静的型付けの魅力を損なっているだけに見えるな。「dynamic
型はより自然に見えるコードを書けるように影で働く」のならばずっと影に潜んでいたまえ。
やべ、ジェネリックと
object
との違いがわからなくなってきた。
ちなみに冒頭のこの疑問については……うーん、単純に、ジェネリックメソッドでは全部の引数が同じ型になるけど、 dynamic
メソッドはその限りではない、くらいの納得でいいかな。
// a と b は違う型でも OK。
public static dynamic UseObjects(dynamic a, dynamic b)
// a と b は同じ型じゃないとダメ。
public static T UseObjects<T>(T a, T b)