starrynight92
starrynight92

Reputation: 105

the filtering in Scala's for loop

I'm a new beginner to Scala, and I'm now learning the for statements. I read this tutorial http://joelabrahamsson.com/learning-scala-part-six-if-statements-and-loops/

And in this tutorial, there is a example,

for (person: Person <- people
    if !person.female;
    name = person.name;
    if name.contains("Ewing"))
  println(name)

If compare this for loop to the for loop in Java, is it like

for(person: people) {
   if (!person.female) {
     String name = person.name;
     if (name.contains("Ewing"))   
       println(name)
   }
}

or like this:

for(person: people) {
   String name = person.name;
   if (!person.female && name.contains("Ewing")) {
     println(name)
   }
}

Are the operations (in this example, name = person.name;) executed if the first filter condition "if !person.female;" is not satisfied?

Thanks!

Upvotes: 2

Views: 1946

Answers (4)

Jatin
Jatin

Reputation: 31724

To see what the scala compiler generates, compile as scalac -Xprint:typer. It gives:

  people.withFilter(((check$ifrefutable$1: typer.Person) => check$ifrefutable$1: @scala.unchecked match {
  case (person @ (_: Person)) => true
  case _ => false
}))
//filter is acting as your if-clause
.withFilter(((person: Person) => person.<female: error>.unary_!)).map(((person: Person) => {
  val name = person.name;
  scala.Tuple2(person, name)
}))
//Your next if-clause
.withFilter(((x$1) => x$1: @scala.unchecked match {
  case scala.Tuple2((person @ (_: Person)), (name @ _)) => name.contains("Ewing")
}))
//Print each of them
.foreach(((x$2) => x$2: @scala.unchecked match {
        case scala.Tuple2((person @ (_: Person)), (name @ _)) => println(name)
      }))
    }
  }

So in short it as acting as your first mentioned case. But as a concept, it is always recommended to think for-comprehensions as a mapping of map, foreach, flatmap etc.

This is because in many cases while dealing with yield you will need to manage types and thinking in terms of foreach and filter (which in java sense is foreach and if) will not cover all cases. For example, consider below:

scala> for(x <- Option(1);
     | u <- scala.util.Left(2)
     | ) yield (x,u)
<console>:9: error: value map is not a member of scala.util.Left[Int,Nothing]
              u <- scala.util.Left(2)

Above for comprehension uses flatmap and map. Thinking in terms of Java for loops (foreach basically`) will not help in finding the reason.

Upvotes: 1

clancer
clancer

Reputation: 613

I think it would not evaluate the follows expressions as it is a common implementation to do so with AND conditions. You can see here
http://www.scala-lang.org/api/current/index.html#scala.Boolean
That scala also has this short circuit implementation when using &&

Upvotes: 0

dhg
dhg

Reputation: 52681

Try it out!

for{
  x <- 1 to 10
  if x % 3 == 0
  y = println(f"x=$x")
  if x % 2 == 0
} {
  println(x)
}

prints:

x=3
x=6
x=9
6

So this means that the y= line is happening before the second if filter.

Upvotes: 1

yǝsʞǝla
yǝsʞǝla

Reputation: 16412

Scala for comprehension unfolds into combination of map, flatmap and filter. In your case if is actually a filter for all values that appear before it in this "iteration" of the "loop". So if if condition is not satisfied the loop will skip this iteration, so your Java for loops behave the same way as Scala example.

For example try this in REPL:

scala> val l = List(1, 2, 3, 4, 5, 6)
l: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> for (i <- l
     |      if(i%2 == 0))
     |      println(i)
2
4
6

scala> 

This is equivalent to:

l.filter(_%2 == 0).foreach(println)

Upvotes: 1

Related Questions