Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - difference between for each loops

Is there any difference between the two following statements. They achieve the same end, correct? Do they compile to the same Java code? Is there any performance difference between them or is it just a matter of preference/readability?

for (thing <- things) {
    doSome(thing)
}

things.foreach(
  thing =>
    doSome(thing)
)
like image 267
Sean Connolly Avatar asked May 24 '13 21:05

Sean Connolly


3 Answers

They are identical. Given

class Foreach {
  val things = List(1,2,3)
  def doSome(i: Int) { println(i) }
  def one { for (thing <- things) { doSome(thing) } }
  def two { things.foreach{ thing => doSome(thing) } }
}

the bytecode is

public void one();
  Code:
   0:   aload_0
   1:   invokevirtual   #40; //Method things:()Lscala/collection/immutable/List;
   4:   new #42; //class Foreach$$anonfun$one$1
   7:   dup
   8:   aload_0
   9:   invokespecial   #46; //Method Foreach$$anonfun$one$1."<init>":(LForeach;)V
   12:  invokevirtual   #52; //Method scala/collection/immutable/List.foreach:(Lscala/Function1;)V
   15:  return

public void two();
  Code:
   0:   aload_0
   1:   invokevirtual   #40; //Method things:()Lscala/collection/immutable/List;
   4:   new #55; //class Foreach$$anonfun$two$1
   7:   dup
   8:   aload_0
   9:   invokespecial   #56; //Method Foreach$$anonfun$two$1."<init>":(LForeach;)V
   12:  invokevirtual   #52; //Method scala/collection/immutable/List.foreach:(Lscala/Function1;)V
   15:  return
like image 66
Rex Kerr Avatar answered Sep 28 '22 19:09

Rex Kerr


for comprehensions are defined as simple syntactic translations. That's extremely important, because that allows any object to work with for comprehensions, it just has to implement the right methods.

IOW: the Scala Language Specification says that the first snippet gets translated into the second. So, if there were any difference whatsoever between the two snippets, that would be a violation of the spec and thus a very serious compiler bug.

Some people have asked for, and even implemented, special treatment of certain objects (e.g. Ranges), but those patches were always rejected with the argument that special treatment for special types would only benefit those special types, whereas making Scala faster in general will benefit everybody.

Note that with Macros, it's probably possible to detect, say, iteration over a Range purely as a simple C style for loop and transform that into a while loop or a direct tailrecursive inner function, without having to change the spec or add special casing to the compiler.

like image 36
Jörg W Mittag Avatar answered Sep 28 '22 21:09

Jörg W Mittag


Per scala-lang.org:

As always, for-expressions can be used as an alternate syntax for expressions involving foreach, map, withFilter, and flatMap, so yet another way to print all elements returned by an iterator would be:

for (elem <- it) println(elem)

"Alternate syntax" would mean identical.

like image 22
djechlin Avatar answered Sep 28 '22 19:09

djechlin