0

I tried to make an example to explain that the placeholder _ without parentheses can represent (be expanded to) any number of parameters with any type, not just can represent "only one" parameter with any type. However, the one I made was incorrect since the parameter (function literal) of foreach would still take one parameter only.
// The following code to explain the placeholder rule above is incorrect.
I made a modified example to expound this rule simply.

val list1 = List(1,2,3)
val list2 = List((1,2),(3,4),(5,6))
val list3 = List((1,2,3),(4,5,6),(7,8,9))
scala> list1.foreach(println _) // _ is expanded to 1 parameter in each iteration
1
2
3

scala> list2.foreach(println _) // _ is expanded to 2 parameters in each iteration
(1,2)
(3,4)
(5,6)

scala> list3.foreach(println _) // _ is expanded to 3 parameters in each iteration
(1,2,3)
(4,5,6)
(7,8,9)

This might be able to explain the rule more clearly.
I hope it is correct.

// The original question
In Chapter 8.6 PARTIALLY APPLIED FUNCTIONS of the book Programming in Scala, 3rd Edition, An example shows:

val list = List(1,2,3)
list.foreach(x => println(x))

The context says the function literal

println _

can substitute for

x => println(x)

because the _ can represent an entire parameter list.

I know an underscore leaving a space between itself and the function name (println, in this case) means the underscore represents an entire parameter list.
In this case, however, there is only one parameter (the Int element of each iteration) in the original function literal.
Why does this tutorial say _ represents an entire parameter list?

The function literal

x => println(x) // Only one parameter? Where's the entire parameter list? 

in

list.foreach(x => println(x))

obviously has only one parameter, correct?

Julia Chang
  • 181
  • 1
  • 8
  • 1
    There is actually a difference between `foreach(println(_))` and `foreach(println _)`. The first one is equivalent to `foreach(x => println(x))` and the second one is equivalent to `foreach(println)`. - So, the first one is actually _sugar syntax_ for a **lambda** of just one argument that you will only use one time. The second one is called [**eta-expansion**](https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#eta-expansion-section) which converts a method expression to a function expression of the same number and type of arguments, `println _` is the explicit way of using it. – Luis Miguel Mejía Suárez Dec 16 '19 at 13:44
  • 2
    Eta-expansion is _also_ syntax sugar for the same lambda in this context (see [Method Values on the same page](https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#method-values)). The difference for `println` has to do with overloads. – Alexey Romanov Dec 16 '19 at 14:08
  • I made a modified example in the edit to expound "placeholder _ without parentheses can represent any number of parameters". I hope it is correct. – Julia Chang Dec 18 '19 at 09:21
  • 1
    Your updated explanation is not correct. `println()` can only take 1 parameter. In your 2nd and 3rd examples the underscore `_` represents a single tuple. – jwvh Dec 18 '19 at 09:36
  • How do I make an example in which a method takes one parameter having two or more parameters in each iteration? – Julia Chang Dec 18 '19 at 11:03
  • 1
    Your question is self-contradictory. How can a method that takes 1 parameter then take 2 or more? It can't. But if you have a method that takes 2 parameters, `def f(c:Char, n:Int) = ...` for example, then, in that case, a single underscore can be used to represent both parameters: `f _` – jwvh Dec 18 '19 at 18:04

1 Answers1

2

Why does this tutorial say _ represents an entire parameter list?

Because it's talking about the entire parameter list of println. Which has only one parameter.

Do you mean println _ represents println(element1: Int, element2: Int, ... elementN: Int)

No. To determine the meaning of println _ we look at its signature

def println(x: Any): Unit

"The entire parameter list" is (x: Any), so println _ is the same as (x: Any) => println(x). If you have def foo(x: Int, y: Int) = x + y, then foo _ will be (x: Int, y: Int) => foo(x, y).

Note: There is also the overload with no parameters def println(): Unit, but the compiler determines it makes no sense here because foreach expects a function with a single parameter; but e.g. in

val f: () => Unit = println _

println _ is equivalent to () => println() instead of (x: Any) => println(x).

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Do you mean println _ represents println(element1: Int, element2: Int, ... elementN: Int)? – Julia Chang Dec 16 '19 at 13:30
  • In other words, placeholder _ without parentheses can represent (be expanded to) any number of parameters with any type, not just can represent "only one" parameter with its type, correct? If that's the case, the rule saying placeholder _ without parentheses can represent an entire parameter list makes sense. However, the example in the book using a method just taking only one parameter in each iteration seems not a proper one to expound this rule. Is that correct? – Julia Chang Dec 18 '19 at 08:03
  • Yes, pretty much. I would only note that `_` can represent _multiple_ parameter lists as well. – Alexey Romanov Dec 18 '19 at 17:18