Wednesday, December 21, 2011

Groovy, Scala, Java, Xtend - an UPDATED stupid comparison

This is an update to yesterday's post, based on feedback I got so far:

Measurement

Henning suggested that the number of iterations is too small:

10000 iterations are probably not enough for a comparison: If I go from 10k to 100k iterations, the Scala version needs 5x time -- the Java version only 2x.

Indeed. Here's what I got when using 1M iterations:

  • Java (the pretty version):
    Took : 245 ms, number of elements : 3000000
  • Xtend :
    Took : 278 ms, number of elements : 3000000
  • Xtend (using switch - see below) :
    Took : 298 ms, number of elements : 3000000
  • Scala (using for comprehensions) :
    Took : 5140 ms, number of elements : 3000000
  • Scala (using while loops) :
    Took : 931 ms, number of elements : 3000000
  • Scala (using while loops and java.util.collections - see below) :
    Took : 315 ms, number of elements : 3000000
  • Groovy (using << operator - see below):
    Took : 1683 ms, number of elements : 3000000

Groovy

Thorsten and Jochen pointed out that I used the wrong operator for adding new elements to a list. I should use '<<' instead of '+=' since the latter would create a new list for the single elements before adding them. I've fixed this and the Groovy program is much faster now.

Jochen also pointed out that the comparison is unfair since, because of the dynamic dispatch Groovy does heavy caching assuming that a method is invoked for the same type of argument most of the time.

My initial idea was to do a comparison where Groovy has a strength (i.e. dynamic dispatch). After all the other examples also do dispatching at runtime. The Java and Scala version don't call another method, but since Xtend does so and is as fast as Java I'd say this extra call doesn't change much.

Jochen also states:

Imagine a class with those three foo methods written in Java. Then in Groovy you can still run your test. I dare to say that in Xtend you cannot make this work without a dispatcher method somewhere - and your dispatch keyword is implying that - thus I assume you cannot make this then work using a Java class.


I think this is actually a big problem with Groovy. Although it's syntax might look a bit like Java it behaves totally different.
In contrast Xtend binds statically just like Java and in fact a multi method in Xtend behaves always the same no matter if you call it from Java or Xtend.

He further says

But let us not stop here... let us assume that you write the base class in Java, where it knows foo(String) foo(Object) and foo(Boolean). Using this class the Integer variant would call the foo(Object) method in your code. Now extend that class in Java with a foo(Integer) method and Groovy would no longer call foo(Object) but foo(Integer).
I doubt you can easily simulate that case.


I can indeed not do that in Java. But I can do that with Xtend and it still behaves as expected no matter form what language you'd call that code.

Scala

Jan said:

I rewrote your little program to use while loops and the java utils collections and the scala version was as fast as java - but nearly as ugly to :-D

Here's the updated Scala version with while and java.util.collections, which is now almost as fast as the Java version:
object Scala extends Application {
  val absoluteResult = new ArrayList[Any]()
  val before = System.currentTimeMillis()
  var i =0
  while (i<1000000) {
    i = i+1
    val result = List("foo", 23, true).iterator
    while (result.hasNext) {
      absoluteResult.add(foo(result.next))
    }
  }
  println("Took : "+(System.currentTimeMillis() - before)
      +" ms, number of elements : "+absoluteResult.size)
  
  def foo(obj : Any) =
    obj match {
          case _:String => "String"
          case _:Boolean => "Boolean"
          case _:Integer => "Integer"
          case _ => throw new IllegalArgumentException()
    }
}

Clojure

Stefan did a nice little example in Clojure. It doesn't use any mutable collections but uses a pure functional style:

(defn foo [x]
(cond
(number? x) "Number"
(string? x) "String"
(= (class x) Boolean) "Boolean"))

(time (println (count 
(map foo 
(apply concat 
(repeat 10000 ["foo" 23 true]))))))
On his machine the Java example takes '31ms' and the Clojure program prints

Prints:
30000
"Elapsed time: 194.046477 msecs"

Xtend

An alternative way to do the dispatch in Xtend is using type guards in switch,
which doesn't make a huge difference performance-wise :

class XtendWithSwitch {
  def static void main(String[] args) {
    val absoluteResult = newArrayList()
    val before = System::currentTimeMillis()
    for (times : 0..1000000) {
      val result = newArrayList('foo', 23, true)
      for (y : result) {
        absoluteResult += foo(y)
      }
    }
    println("Took : "+(System::currentTimeMillis() as int - before)
      +" ms, number of elements : "+absoluteResult.size)
  }

  def static foo(Comparable comp) {
    switch(comp) {
      String : 'String'
      Boolean : 'Boolean'
      Integer : 'Integer'
      default : throw new IllegalArgumentException()
    }  
  }
}

Java


Finally based on Henning's suggestion I beautified the Java version a bit using Guava and static imports:

public static void main(String[] args) {
  List<Object> absoluteResult = newArrayList();
  long before = System.currentTimeMillis();
  for (int i=0; i < 1000000; i++) {
    for (Object y : newArrayList("foo", 23, true)) {
      absoluteResult.add(foo(y));
    }
  }
  System.out.println("Took : "+(System.currentTimeMillis() - before)
    +" ms, number of elements : "+absoluteResult.size());
}

static String foo(Object s) {
  if (s instanceof String) {
    return "String";
  } else if (s instanceof Boolean) {
    return "Boolean";
  } else if (s instanceof Integer) {
    return "Integer";
  } else {
    throw new IllegalArgumentException();
  }
}

Tuesday, December 20, 2011

Groovy, Scala, Java, Xtend - a stupid comparison

Disclaimer: This is probably the worst possible way to compare execution performance. I'm posting it nonetheless since the result was significant. Judge for yourself.

Today I took some time to check out the latest Eclipse plugins for both Groovy and Scala. I mainly wanted to know how nice the tooling is and played around with it a bit. I had been doing some Scala a couple of years ago, but since the Eclipse plugin not even existed those days it was a bit too painful for me to get used to it.

Groovy's tooling looks very good. There are just a few oddities but mainly I think it's well done... in contrast to the Scala plugin (I used 2.0.0 RC4). It holds a lot of surprises. For instance, with the Scala-IDE installed you'll get Scala-related template proposals in the Java and the Groovy editor. Still Scala the language would be my personal choice if I had to decide between the two. Anyway, this post is not about language features or Eclipse-plugin quality, but about what I experienced regarding runtime performance.

I knew Groovy's performance is bad. But I expected the performance problems to diminish, if I use a scenario using dynamic dispatch and mostly untyped objects. So I wrote the following brain dead code:

class Groovy {

  public static void main(String[] args) {
    def absoluteResult = []
    def before = System.currentTimeMillis()
    for (times in 1..10000) {
      def result = ['foo', 23, true]
      for (y in result) {
        absoluteResult += foo(y)
      }
    }
    println("Took : "+(System.currentTimeMillis() - before)
      +" ms, number of elements : "+absoluteResult.size);
  }

  static String foo(String s) {
    'String'
  }
  
  static String foo(Boolean s) {
    'Boolean'
  }
  
  static String foo(Integer s) {
    'Integer'
  }

}

It doesn't do anything interesting but leverages Groovy's built-in way of resolving overloaded methods using the runtime type. I thought it's fair to use this feature in a comparison, also because Xtend's dispatch methods have the same behavior. The result of the code above would be a list containing the string 'String', 'Boolean', and 'Integer' each 10.000 times.

When I run this code on my machine, it prints something like the following:

Took : 2025 ms, number of elements : 30000

A possible Xtend version

This is how I could achieve the same using Xtend:

class Xtend {
  def static void main(String[] args) {
    val absoluteResult = newArrayList()
    val before = System::currentTimeMillis()
    for (times : 1..10000) {
      val result = newArrayList('foo', 23, true)
      for (y : result) {
        absoluteResult += foo(y)
      }
    }
    println("Took : "+(System::currentTimeMillis() - before)
           +" ms, number of elements : "+absoluteResult.size)
  }

  def static dispatch foo(String s) {
    'String'
  }
  
  def static dispatch foo(Boolean s) {
    'Boolean'
  }

  def static dispatch foo(Integer s) {
    'Integer'
  }
}

On a first glance it looks very similar. Note, the dispatch keyword, which turns a set of overloaded methods into dynamically dispatched methods (i.e. the default Groovy behavior).
In contrast to the Groovy version this one is fully statically typed and as it turned out much faster. (Again as you see my measurement technique is everything but professional, but given such a big difference I dare to say it's faster).

It prints something like:

Took : 43 ms, number of elements : 30000

I also did a Scala version:


object Scala extends Application {
  val absoluteResult = MutableList[Any]()
  val before = System.currentTimeMillis()
  for (times <- 0 until 10000) {
    val result = List("foo", 23, true)
    for (y <- result) {
      absoluteResult += foo(y)
    }
  }
  println("Took : "+(System.currentTimeMillis() - before)
      +" ms, number of elements : "+absoluteResult.size)

  def foo(obj : Any) =
    obj match {
          case _:String => "String"
          case _:Boolean => "Boolean"
          case _:Integer => "Integer"
          case _ => throw new IllegalArgumentException()
    }
}

I got this kind of result:

Took : 130 ms, number of elements : 30000

And finally a Java version:

public class Java {
  public static void main(String[] args) {
    List<Object> absoluteResult = new ArrayList<Object>();
    long before = System.currentTimeMillis();
    for (int i=0; i < 10000; i++) {
      List<Object> result = new ArrayList<Object>();
      result.add("foo");
      result.add( 23);
      result.add(true);
      for (Object y : result) {
        absoluteResult.add(foo(y));
      }
    }
    System.out.println("Took : "+(System.currentTimeMillis() - before)
      +" ms, number of elements : "+absoluteResult.size());
  }

  static String foo(Object s) {
    if (s instanceof String) {
      return "String";
    } else if (s instanceof Boolean) {
      return "Boolean";
    } else if (s instanceof Integer) {
      return "Integer";
    } else {
      throw new IllegalArgumentException();
    }
  }
}

Which prints:

Took : 40 ms, number of elements : 30000

Monday, December 12, 2011

Writing Android UIs with Xtend

(Update: You can find the project on github : https://github.com/svenefftinge/xtend-android-experiments )

Xtend is a great fit for Android development. Since Xtend translates to Java source code, it's very easy to use it. After you've installed the Xtend SDK and the Android Development Tools you only need to do two things to get started.
  1. In Eclipse's preferences configure Xtend's compiler to generated to the gen/ folder.
  2. Add the Xtend lib and Google Guava to your project's classpath. 
Why is it useful?
Using a combination of Xtend's powerful extension methods and closures, it's possible to come up with a very declarative API to define UI models. It takes a couple of minutes to write an API which allows for defining a UI like the following:

class AppActivity extends Activity {
 
  override void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  
    contentView = this.linearLayout [
   
      orientation = VERTICAL
  
      view = this.textView ("Hello Android!")
  
      view = this.button ("Click Me!") [
        onClickListener = [ 
          this.textMessage('Hello you clicked me!').show
        ]
      ]
    ]
  } 
}

The API is made available by means of a static extension import. To outline the idea, here's how the button method is defined:

def static button(Context context, String text,
      (Button)=>void initializer) {
  val result = new Button(context)
  result.text = text
  initializer.apply(result)
  return result
}

Used as an extension method button can be invoked on any instance of Context. Since the last argument is a function type it can be passed after the actual method invocation:

view = this.button ("Click Me!") [
        onClickListener = [ 
          this.textMessage('Hello you clicked me!').show
        ]
      ]

Also note how you can simply assign a closure to onClickListener (which is btw. invoking setOnClickListener()). The compiler will automatically convert it to an abstract class of View.OnClickListener.
And everything is 100% statically typed!