How Scala Compiles to Java
iamchrislewis.tumblr.com
iamchrislewis.tumblr.com
Another post that I'd like to read would be: How Many Objects Does Scala Allocate (while executing some random code).
In my Java shop, we try to write ultra-efficient code. Avoiding the creation of numerous small objects in critical sections is one of the best ways to achieve that.
I'd like to start a couple projects in scala or clojure but I'm afraid that the simplicity and expressiveness that these languages bring come at the cost of performance (or at least on control on what the JVM does).
But even without scala-idioms scala is so much nicer than java that I never want to go back.
http://teh.gitblogs.com/post/how-to-avoid-allocations-when-u...
For reducing the library size see e.g. http://github.com/teh/androidmake
I've seen others do similar things, you'll need to google for their solutions.
Uh, why? Are all object types known at runtime in Clojure? I bet they are. And this is exactly what Hotspot was designed to make fast [1].
However the Clojure implementations on the site are still quite young, so some improvement may be possible.
[1] http://shootout.alioth.debian.org/u32/benchmark.php?test=all...
The Shootout probably wont show good results for this because it takes a little bit for Hotspot to get the most out of it. If you look at the Mandelbrot demo in Strongtalk it takes about 3 full runs to get the best speed.
How much work the code that they generate does. Clojure is mostly pure right? If you have, e.g. a btree and you change some nodes the old notes won't get deleted, a new tree will be created where some of the nodes point to the still valid old ones and some point to your changes. That's more work then just mutating the variables.
p.s. i'm new to scala (and using it on app engine and android) but have extensive F# and decent haskell and ocaml experience and have found stuff like hyperpolyglot useful but this type of knowledge is not readily found.
http://www.decodified.com/scala/2010/08/27/scala-rich-wrappi...
As other comments have noted you can generally degrade to writing near-Java code and the results will be basically the same bytecode. I'm sure there are exceptions but if you want to, you can avoid object creation. Implicit conversions are one of those cases which will not be called out as a warning or similar, though, so something to be careful of.
I don't know anything about Java, but the Objective-C GC recycles old allocations to avoid this exact problem. For example
for (int i = 0; i < 10000; i++)
{
Foo *foo = [[Foo alloc] init];
}
Instead of allocating memory for foo 10000 times, older allocations are kept in a pool and reused for subsequent iterations. So the actual cost of -alloc is just a memset (i.e. nothing). Java's GCs are much more mature, so I would assume they have the same optimisation.I'd like to know why you think creating numerous small objects is an issue... Short lived small objects should be negligible to an application's performance.
Are you sure you should be doing that? As Knuth said, "premature optimization is the root of all evil".
Otherwise, our #1 priority is that code should be beautiful (concise, readable).
A nice side effect is that sometimes "nicer" also means more efficient (the JVM likes small methods) :)
import scala.Function1;
import scala.List;
import scala.runtime.RichInt;
class App$ {
public static final App$ MODULE$ = new App$();
public boolean isEven(int i) {
return i % 2 == 0;
}
public boolean isOdd(int i) {
return i % 2 == 1;
}
public void main(String[] args) {
final List<Integer> n = (new RichInt(1)).to(10).toList();
n.filter(new Function1<Integer, Boolean>() {
public Boolean apply(final Integer x) {
return isEven(x);
}
}).flatMap(new Function1<Integer, List<Integer>>() {
public List<Integer> apply(final Integer i) {
return n.filter(new Function1<Integer, Boolean>() {
public Boolean apply(final Integer x) {
return isOdd(x);
}
}).map(new Function1<Integer, Integer>() {
public Integer apply(final Integer j) {
return i * j;
}
});
}
});
}
}
class App {
public static boolean isEven(int i) {
return App$.MODULE$.isEven(i);
}
public static boolean isOdd(int i) {
return App$.MODULE$.isOdd(i);
}
public static void main(String[] args) {
App$.MODULE$.main(args);
}
}
Note that, although anonymous inner classes are valid syntax in Java 5, even in Java 5 they are compiled down to separate class files. Hence 2 classes + 4 anonymous inner classes = 6 class files total.(The code is only approximate. I haven't tried to compile it, so apologies for any errors.)