Following Code is from Odersky et al. (p. 167) on "Programming in Scala".
val filesHere = (new java.io.File(".")).listFiles
def fileLines(file: java.io.File) =
scala.io.Source.fromFile(file).getLines().toList
def grep(pattern: String) =
for (
file <- filesHere
if file.getName.endsWith(".scala");
line <- fileLines(file)
if line.trim.matches(pattern)
) println(file +": "+ line.trim)
grep(".*gcd.*")
The code will not compile without it because "the Scala compiler will not infer semi-colons while inside parentheses" (ibid, p. 167). Question 1: Why is the code not equivalent to:
def grep(pattern: String) =
for (
file <- filesHere
if (file.getName.endsWith(".scala")){
line <- fileLines(file)
}
if line.trim.matches(pattern)
) println(file +": "+ line.trim)
grep(".*gcd.*")
Question 2: Why is the semicolon after the first if condition needed in the code above? What role does it play?
Your for-loop has a couple of generators and filters:
for (
file <- filesHere // generator
if file.getName.endsWith(".scala"); // filter
line <- fileLines(file) // generator
if line.trim.matches(pattern) // filter
) println(file + ": " + line.trim)
In Scala, generators and corresponding filters can be placed within a for comprehension
. This link might give a little more details on the very topic.
As to the semi-colon, it's needed just exactly as the compiler says: the Scala compiler will not infer semi-colons while inside parentheses
.
Your for-loop is no difference from:
for (
file <- filesHere if file.getName.endsWith(".scala");
line <- fileLines(file) if line.trim.matches(pattern)
) println(file + ": " + line.trim)
Enclosing a code block with braces { ... }
allows you to skip the requirement of explicit semi-colons.