Java8のLambdaの型推論が実行時にならいと型が分からない理由(追記あり)
JJUGナイトセミナー「Inside Lambda」に参加してきました。
Java8のLambdaの概要と、実装方法についてのお話でした。
非常に面白かったのですが、その中でLambdaの型推論が実行時にならいと型が分からないという話があったのでまとめてみます。
Lambdaの型推論
Lambda式の中ではコンパイラが推測できる場合は型を省略する事が可能です。
Comparator<Integer> comp = (x , y) -> x -y;
しかし、実際に型が決まるのはコンパイル時ではなく実行時になります。
それはなぜでしょうか?
Lambdaの実装
その答えは、ナイトセミナーの宮川さんの発表で理解できました。
それは、Lambdaがinvokedynamicを使って実装されているからです。
invokedynamicについては・・・これまた宮川さんの資料が分かりやすいです。
私の理解では、
- JVMで実際にメソッドを実行したりするのがInvokeなんたらのお仕事
- その中でもinvokedynamicはJava以外の動的型付け言語をJVMで動かすための機能
- そのためinvokedynamicは実行中にクラスファイルを動的に生成したりできる
という感じです。
で、Java8のLambdaはinvokedynamicを使って実装されているそうです。
そのため、実際に型が分かるのが実行時ということになります。
仕様?
@nagaseyasuhito いえ、違います。invokedynamicを使うかどうかは実装の問題です。 #jjug
— Yuichi Sakuraba (@skrb) 2013, 7月 22
@nagaseyasuhito invokedynamicが使われていないで、コンパイル時に無名クラスを作っていた時代もありましたよ ^ ^;;; #jjug
— Yuichi Sakuraba (@skrb) 2013, 7月 22
実装がたまたまそうなっている、という話だそうです。
なのでJava8が正式リリースされた時には、ひょっとしたらコンパイル時に型が決まるようになっているかもしれませんね。
実害はあるのか?
ちょっと考えてみたのですが思いつきませんでした。
実行時に決まるからどんな型になるかわからない?!って事はないですよね、これ。
あくまでコンパイラも型推論チェックをやっているので、実際に予期せぬ型になってしまうことはなさそうです。
まとめ
Scalaを使おう!
追記
きしださんからコメントをもらいました。
@sakamoto_desu 「型推論が実行時にならいと型が分からない」というの、「型がわからない」という表現は違うと思います。型は「Comparator<Integer>」だとわかっているので。
— きしだ (@kis) 2013, 7月 26
@sakamoto_desu 型推論としてはコンパイル時に「Comparator<Integer>」だと確定した時点で型が決まって、これ以上は型推論の話ではないです。
— きしだ (@kis) 2013, 7月 26
@sakamoto_desu そうですそうです。Runnable r = hoge(); で、hogeメソッドが返してきて実際に変数rに割り当てられるインスタンスの型が実行時まで決まらないのと、言語上でやってるかVM上でやってるかの違いだけで同じものという感じです。
— きしだ (@kis) 2013, 7月 26
というわけで、正確には「ラムダ式の型は実行時にならないと決まらない」という話でした。
タイトルも含めて書き直そうかとも思ったのですが、きしださんにコメントもらえた記念ということで追記だけにしておきます。