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 ).

链接地址: http://www.djcxy.com/p/37224.html

上一篇: 检查块是否有区别

下一篇: 为什么Java8和Scala2.12 lambda缓存有区别?