Kermit Wang
Kermit Wang

Reputation: 13

I (a beginner) feel underscore is confusing

I'm trying to learn programming with Scala, and I met some problem about the underscore.Here is the code:

FileMatcher.filesContaining("hello").foreach(println(_))

FileMatcher.filesContaining("hello").foreach(println((_:java.io.File).getName))

My question is, if underscore represent the formal parameter of a function(right?, i have seen some answer about underscore), why the first code runs well, but the second crashed?

=====================================================================

the whole code(sorry for my poor english. "crashed" means compile failed)

object FileMatcher{

  private def filesHere = (new java.io.File(".")).listFiles

  def filesMatching(query: String, matcher: (String, String) => Boolean) =
    for (file <- filesHere if matcher(file.getName, query))
      yield file

  def filesEnding(query: String) =
    filesMatching(query, _.endsWith(_))

  def filesContaining(query: String) =
    filesMatching(query, _.contains(_))

}

FileMatcher.filesContaining("hello").foreach(println(_))

FileMatcher.filesContaining("hello").foreach(println((_:java.io.File).getName))

Upvotes: 0

Views: 121

Answers (1)

0__
0__

Reputation: 67280

val seq: Seq[java.io.File] = Seq(new java.io.File("hello"))

In here:

seq.foreach(println(_))

...the underscore replaces the argument of println with the argument of an anonymous function (the function that is passed to foreach). This is equal to

seq.foreach(f => println(f))

In fact you could even shorten this to:

seq.foreach(println)

Whereas in:

seq.foreach(println(_.getName))

...you would pass a function x => x.getName to println. This doesn't compile because now you are ignoring that foreach takes a function of arity 1. You could for example attempt to write:

seq.foreach(f => println(_.getName))

Then still Scala has no idea what the argument type of x => x.getName is (because there is no context from which it could infer that). So:

seq.foreach(f => println((x: java.io.File) => x.getName))

The output:

<function1>

Ooops. That's not what you wanted. You are printing the string representation of a function (without applying the function). Obviously, you are also not doing anything with f. So you see, the inner function is one bubble too much.

Correct is:

seq.foreach(f => println(f.getName))

Scala doesn't allow you to shorten this to seq.foreach(println(_.getName)) because there is something in the middle between foreach and getName and that is the println method.

Upvotes: 5

Related Questions