Sumit Pal
Sumit Pal

Reputation: 443

Why do one of these split & filter work but not the other?

val c = s.split(" ").filter(_.startsWith("#")).filter(x =>  
  x.contains("worcester") || x.contains("energy"))

Works

But this does not

val c = s.split(" ").filter(_.startsWith("#")).filter(_.contains("worcester") || 
  _.contains("energy"))

I have not understood it clearly why the latter does not work - may be I have a flaw in my fundamentals

Any help would be very appreciated thanks Sumit

Upvotes: 1

Views: 301

Answers (1)

Ben Reich
Ben Reich

Reputation: 16324

Using underscore like this is known as placeholder syntax. So, something like _.contains("x") is equivalent to x => x.contains("x"). You can only use each parameter once when using the placeholder syntax. Using multiple placeholders denotes multiple parameters of the anonymous function (which are then used in order of the underscores). So, when you write:

o.filter(_.contains("worcester") || _.contains("energy"))

It would theoretically be equivalent to

o.filter((x, y) => x.contains("worcester") || y.contains("energy"))

Which doesn't type check, since filter expects a parameter of type Array[String] => Boolean.

Multiple placeholders are common when using the reduce variants. For example, a factorial can be computed as (1 to n).reduce(_ * _). This works because reduce expects a parameter of type (Int, Int) => Int, so _ * _, which is equivalent to (x, y) => x * y fits the expected type.

It's important to note that the placeholder syntax applies to the smallest possible scope. So, for example, f(g(_)) is equivalent to f(x => g(x)), and not x => f(g(x)), which is a common mistake.

You can find a comprehensive list of the use of underscore in Scala here, and a little bit more about the placeholder syntax here.

Upvotes: 5

Related Questions