2016-11-24 47 views
7

Java kodDlaczego jest różnica między pamięcią podręczną lambda Java 8 i Scala2.12?

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

kod Scala (wersja 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 
    } 
} 

wynik

$ 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/2[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 

Odpowiedz

3

Scala ma ścieżek zależny od rodzaju. Chociaż nie jest to oczywiste z twojego przykładu, można skonstruować zagnieżdżone cechy, w których cecha Foo w jednym z nich na przykład Semigroup2 nie jest w żaden sposób zgodna z Foo z innej instancji Semigroup2. This post i this answer wydają się być dobrym wyjaśnieniem typów zależnych od ścieżki.

Oznacza to, że instancja Semigroup2 jest zdefiniowana również przez jej wewnętrzną cechę, więc zamknięcie musi zostać wykonane podczas odwoływania się do jednej z jej metod. Ponieważ zamknięcie to jest ponownie wykonywane w locie za każdym razem, gdy próbujemy odwoływać się do tej metody, nie jest zaskakujące, że anonimowe funkcje są różne.

W języku Java tak nie jest. Semigroup2<A>.Foo to typ (inaczej niż w Scali, gdzie potrzebna jest instancja z Semigroup[A] do identyfikacji typu Foo).

+0

Najbliższym odpowiednikiem Java dla zachowania Scala byłoby, gdyby lambda main :: intSemigroup2 przechwyciła instancję Semigroup2.Foo, jak (a1 + a2) -> {foo.hashCode(); return a1 + a2; }). Zmusiłoby to Main :: intSemigroup2 do zawsze zwracania nowej wartości lambda, ponieważ Java nie ma gwarancji, że przechwycona wartość Foo jest wbudowana. – srborlongan

+1

@srborlongan Przypuszczam, że tak - Myślałem o tym bardziej jako "dlaczego Scala nie zwraca tej samej funkcji", w przeciwieństwie do "dlaczego Java nie zwraca różnych funkcji." "Dobry punkt" – Alec