2016-11-24 3 views
7

Java-CodeWarum gibt es einen Unterschied zwischen Java8 und Scala2.12 Lambda Cache?

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 
    } 
} 

Ergebnis

$ 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/[email protected] 
lambda_cache_example_java.Main$$Lambda$9/[email protected] 
true 
lambda_cache_example_java.Main$$Lambda$10/[email protected] 
lambda_cache_example_java.Main$$Lambda$10/[email protected] 
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/[email protected] 
lambda_cache_example_scala.Main$$$Lambda$11/[email protected] 
true 
[email protected] 
[email protected]9 
false 
[success] Total time: 0 s, completed 2016/11/24 15:09:57 

Antwort

3

Scala hat pfadabhängige Typen. Obwohl aus Ihrem Beispiel nicht offensichtlich, könnte man verschachtelte Eigenschaften konstruieren, wo das Merkmal Foo in einem von zum Beispiel Semigroup2 mit der Foo von einer anderen Instanz Semigroup2 überhaupt nicht kompatibel ist. This post und this answer scheinen gute Erklärungen für pfadabhängige Typen zu sein.

Dies bedeutet, dass eine Instanz von Semigroup2 auch durch ihre innere Eigenschaft definiert ist, so dass eine Schließung vorgenommen werden muss, wenn eine ihrer Methoden referenziert wird. Da diese Schließung jedes Mal, wenn wir versuchen, auf diese Methode zu referenzieren, neu erstellt wird, ist es nicht überraschend, dass die anonymen Funktionen unterschiedlich sind.

In Java ist dies nicht der Fall. Semigroup2<A>.Foo ist ein Typ (anders als in Scala, wo Sie eine Instanz von Semigroup[A] benötigen, um einen Typ Foo zu identifizieren).

+0

Das nächste Java-Äquivalent für das Verhalten von Scala wäre, wenn das Lambda von Main :: intSemigroup2 eine Semigroup2.Foo-Instanz erfasst, wie (a1 + a2) -> {foo.hashCode(); zurückgeben a1 + a2; }). Dies würde dazu führen, dass Main :: intSemigroup2 immer ein neues Lambda zurückgibt, da Java nicht garantiert, dass der erfasste Foo-Wert inline-fähig ist. – srborlongan

+1

@srborlongan Ich nehme an - ich dachte an die Frage mehr als "warum Scala nicht die gleiche Funktion zurückgibt" im Gegensatz zu "warum Java nicht verschiedene Funktionen zurückgibt. Guter Punkt. – Alec

Verwandte Themen