Java8のラムダとScala 2.12(LambdaMetafactoryによるシングルトンのキャッシュ)

結論から言うと、Scalaでも以下と同じように頑張るようになるんやで、なので2.12以降はSAMかつ純粋なシングルトンにできる場合は、明示的にnewしないほうが効率いいかもしれないよ、という話


https://twitter.com/orekyuu/status/790753654114357248




http://www.slideshare.net/miyakawataku/lambda-meets-invokedynamic/41
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/invoke/LambdaMetafactory.html



以下、Scalaでの実験結果

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> def foo: Int => Int = a => a
foo: Int => Int

scala> val a1 = foo
a1: Int => Int = <function1>

scala> val a2 = foo
a2: Int => Int = <function1>

scala> a1 eq a2 // 2.11.8までは違うインスタンス生成される
res0: Boolean = false
16:28 $ scala
Welcome to Scala 2.12.0-RC2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> def foo: Int => Int = a => a
foo: Int => Int

scala> val a1 = foo
a1: Int => Int = $$Lambda$1089/1929969663@6601cc93

scala> val a2 = foo
a2: Int => Int = $$Lambda$1089/1929969663@6601cc93

scala> a1 eq a2 // 2.12以降は、キャッシュされてる
res0: Boolean = true
Welcome to Scala 2.12.0-RC2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> import java.lang.ref.WeakReference
import java.lang.ref.WeakReference

scala> val a = new WeakReference[Runnable](new Runnable{def run = println("a")})
a: java.lang.ref.WeakReference[Runnable] = java.lang.ref.WeakReference@26d820eb

scala> val b = new WeakReference[Runnable](() => println("b"))
b: java.lang.ref.WeakReference[Runnable] = java.lang.ref.WeakReference@45bb2aa1

scala> System.gc

scala> a.get
res1: Runnable = null

scala> b.get
res2: Runnable = $$Lambda$1137/1742235652@778d82e9


Scalaライブラリ内での関連コードは以下


雑にキャッシュして逆に遅くなったり、変にバグったら大変なので、Scalaコンパイラの中の人達*1は、結構いろいろベンチマークして頑張ってた気はする。
詳細を解説できるほど詳しくはないので、もっと詳しく知りたい人は、あとは適当に上記の2つのファイルのコミット履歴あたりから辿ってください。


あとちなみに、重大なバグが見つからなければ、これ書いてる時点からもう1週間もしないうち(つまり2016年10月中)に、2.12.0 final出そうです。

*1:主にこのあたり担当の https://github.com/retronym さん