Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 717
Kenji Yoshida Avatar asked Nov 24 '16 06:11

Kenji Yoshida


People also ask

What is the difference between Scala vs Java?

When considering Sala vs. Java, you should know some of Java’s notable drawbacks. Java consumes more memory and is significantly slower than natively compiled languages like C or C++ Java’s default GUI applications written in Java and the Swing toolkit look quite different from native applications What Is Scala?

What is the difference between Scala and Java lazy evaluation?

Scala has a “lazy evaluation” feature that allows the programmer to defer time-consuming computations until they’re needed, using the keyword “lazy.” Java has no such option.

Is Java 8 lambda expressions more efficient than anonymous classes?

But, in any case "Lambda Expressions" would probably be more clear in context. You should generally assume Java 8's approach is at least as efficient and possibly more efficient than the anonymous class approach.

What is Scala programming language?

Scala is a general-purpose, high-level, multi-paradigm programming language. It is a pure object-oriented programming language which also provides the support to the functional programming approach. There is no concept of primitive data as everything is an object in Scala.


1 Answers

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

like image 55
Alec Avatar answered Sep 28 '22 15:09

Alec