4

The scala documentation has a code example that includes the following line:

val numberFunc = numbers.foldLeft(List[Int]())_

What does the underscore after the method call mean?

vaer-k
  • 10,923
  • 11
  • 42
  • 59
  • 1
    It's a completely different question with a specific context. @AlexanderAzarov please don't be so hasty to dismiss useful questions. – vaer-k Sep 19 '18 at 17:31
  • While it's not an exact duplicate, the list in the top-voted answer in the linked duplicate does mention partially applied functions. – Andrey Tyukin Sep 19 '18 at 17:47
  • 1
    @AndreyTyukin a tangential mention of "partially applied functions", a term which cannot be expected to be familiar to the asker of this question, is not enough to justify the duplicate label. The syntax used even in that example is totally different than that used in the question here. There is no justifying the expectation that a person with this question would find the answer there. – vaer-k Sep 19 '18 at 18:30

2 Answers2

9

It's a partially applied function. You only provide the first parameter to foldLeft (the initial value), but you don't provide the second one; you postpone it for later. In the docs you linked they do it in the next line, where they define squares:

val numberFunc = numbers.foldLeft(List[Int]())_
val squares = numberFunc((xs, x) => xs:+ x*x)

See that (xs, x) => xs:+ x*x, that's the missing second parameter which you omitted while defining numberFunc. If you had provided it right away, then numberFunc would not be a function - it would be the computed value.

So basically the whole thing can also be written as a one-liner in the curried form:

val squares = numbers.foldLeft(List[Int]())((xs, x) => xs:+ x*x)

However, if you want to be able to reuse foldLeft over and over again, having the same collection and initial value, but providing a different function every time, then it's very convinient to define a separate numbersFunc (as they did in the docs) and reuse it with different functions, e.g.:

val squares = numberFunc((xs, x) => xs:+ x*x)
val cubes = numberFunc((xs, x) => xs:+ x*x*x)
...

Note that the compiler error message is pretty straightforward in case you forget the underscore:

Error: missing argument list for method foldLeft in trait LinearSeqOptimized Unapplied methods are only converted to functions when a function type is expected. You can make this conversion explicit by writing foldLeft _ or foldLeft(_)(_) instead of foldLeft. val numberFunc = numbers.foldLeft(ListInt)

EDIT: Haha I just realized that they did the exact same thing with cubes in the documentation.

slouc
  • 9,508
  • 3
  • 16
  • 41
  • Why isn't the underscore surrounded by parentheses? Does this work for methods *and* functions? Are `method()(_)` `method()_` and `method() _` all the same then? – vaer-k Sep 19 '18 at 17:25
  • 1
    All three will work the same, yes. As for method vs function, underscore is needed when you provide a method where compiler doesn't expect a function. If the compiler expected a function (e.g. you explicitly typed the value you're asigning to), then it can automatically convert the method into it. But here's some general meta-advice: don't learn this by heart. Just make sure you understand the concepts of partially applied functions and currying; for syntax itself, compiler will always give you a hand and suggest an underscore where needed. Eventually you will get the feeling for it yourself. – slouc Sep 19 '18 at 18:00
2

I don't know if it helps but I prefer this syntax

val numberFunc = numbers.foldLeft(List[Int]())(_)

then numberFunc is basically a delegate corresponding to an instance method (instance being numbers) waiting for a parameter. Which later comes to be a lambda expression in the scala documentation example

PilouPili
  • 2,601
  • 2
  • 17
  • 31