Why is there a difference between Java8 and Scala2.12 lambda cache?
Java code
package lambda_cache_example_java;
interface Semigroup1<A> {
public A append(A a1, A a2);
}
interface Semigroup2<A> {
public A append(A a1, A a2);
public interface Foo{}
public class Bar{}
}
class Main {
static Semigroup1<Integer> intSemigroup1() {
return (a1, a2) -> a1 + a2;
}
static Semigroup2<Integer> intSemigroup2() {
return (a1, a2) -> a1 + a2;
}
public static void main(String[] args) {
Semigroup1<Integer> x1 = intSemigroup1();
Semigroup1<Integer> x2 = intSemigroup1();
System.out.println(x1);
System.out.println(x2);
System.out.println(x1 == x2); // same instance
Semigroup2<Integer> y1 = intSemigroup2();
Semigroup2<Integer> y2 = intSemigroup2();
System.out.println(y1);
System.out.println(y2);
System.out.println(y1 == y2); // same instance as well
}
}
Scala code (version 2.12.0)
package lambda_cache_example_scala
trait Semigroup1[A] {
def append(a1: A, a2: A): A
}
trait Semigroup2[A] {
def append(a1: A, a2: A): A
trait Foo
}
object Main {
def intSemigroup1(): Semigroup1[Int] =
(a1, a2) => a1 + a2
def intSemigroup2(): Semigroup2[Int] =
(a1, a2) => a1 + a2
def main(args: Array[String]): Unit = {
val x1 = intSemigroup1()
val x2 = intSemigroup1()
println(x1)
println(x2)
println(x1 eq x2) // same instance
val y1 = intSemigroup2()
val y2 = intSemigroup2()
println(y1)
println(y2)
println(y1 eq y2) // not same
}
}
result
$ sbt "runMain lambda_cache_example_java.Main" "runMain lambda_cache_example_scala.Main"
[info] Running lambda_cache_example_java.Main
lambda_cache_example_java.Main$$Lambda$9/1908283686@44939bb7
lambda_cache_example_java.Main$$Lambda$9/1908283686@44939bb7
true
lambda_cache_example_java.Main$$Lambda$10/2119574930@7f206457
lambda_cache_example_java.Main$$Lambda$10/2119574930@7f206457
true
[success] Total time: 0 s, completed 2016/11/24 15:09:56
[info] Running lambda_cache_example_scala.Main
lambda_cache_example_scala.Main$$$Lambda$11/2085010450@7b408c6e
lambda_cache_example_scala.Main$$$Lambda$11/2085010450@7b408c6e
true
lambda_cache_example_scala.Main$$anonfun$intSemigroup2$2@c5329e5
lambda_cache_example_scala.Main$$anonfun$intSemigroup2$2@752d3cd9
false
[success] Total time: 0 s, completed 2016/11/24 15:09:57
Scala has path-dependent types. Although not obvious from your example, one could construct nested traits where the trait Foo
inside of one for instance of Semigroup2
is not at all compatible with the the Foo
from another instance of Semigroup2
. This post and this answer seem like good explanations of path dependent types.
This means that an instance of Semigroup2
is defined also by its inner trait, so a closure must be made when referencing one of its methods. Since that closure is re-made on the fly every time we try to reference that method, it isn't surprising the anonymous functions are different.
In Java, this is not the case. Semigroup2<A>.Foo
is a type (unlike in Scala where you need an instance of Semigroup[A]
to identify a type Foo
).
上一篇: 检查块是否有区别