1

When I define this function, I can call it without a problem:

scala> val c = (_: String) + "sd"
c: String => String = <function1>

scala> c("1")
res13: String = 1sd

However if I let the above function print the result without returning it, I have the following error:

scala> val b = print((_: String) + "sd")
<function1>b: Unit = ()

scala> b("1")
<console>:26: error: Unit does not take parameters
       b("1")
        ^

I know the system method print returns Unit type, but shouldn't the function b be a function that can be called with an argument as I defined? Why the above b function can not be called with b("1")?

How to understand and solve the problem? Thank you.

CyberPlayerOne
  • 3,078
  • 5
  • 30
  • 51
  • 2
    Notice how the console returned `b: Unit = ()` for the second case. You did `val b = print(yourFunction1)` and since `print` returns a `Unit` (after printing the provided thing), it printed `` (which is the toString for a Function1) and then `Unit` was assigned to your `b`. – sarveshseri Jan 15 '20 at 06:51
  • 2
    `val b = (s:String) => print(s + "sd")` – jwvh Jan 15 '20 at 06:55
  • The question is now why is `_` not recognised as Input. Are there any rules when it is recognised and when it isn't? – pme Jan 15 '20 at 08:09
  • 3
    I think I know the reason now. The reason is *"The placeholder syntax for anonymous functions replaces the smallest possible containing expression with a function."* In my case in the deifnition of `b`, `(_: String) + "sd"` as such is a ``. So `b` is not a function, it only prints the function1 and returns Unit as @SarveshKumarSingh says. Similar: https://stackoverflow.com/questions/7627117/scala-underscore-error-missing-parameter-type-for-expanded-function – CyberPlayerOne Jan 15 '20 at 08:15
  • 1
    Does this answer your question? [What are all the uses of an underscore in Scala?](https://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala) – Tim Jan 15 '20 at 08:37

2 Answers2

2

Indeed, as you have already discovered

print((_: String) + "sd")

expands to

print((x: String) => x + "sd")

instead of the desired

(x: String) => print(x + "sd")

because _ binds to the innermost expression delimiter () or {}.

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • Which is one of the reasons I always recommend newcomers to avoid the `_` syntax. It is not always clear how it is expanding, it may introduce subtle bugs and finally simple lambda is always more readable due the named parameters. – Luis Miguel Mejía Suárez Jan 15 '20 at 12:19
1

Consider the following sequence.

An anonymous function from String to String.

scala> (_: String) + "sd"
res0: String => String = $$Lambda$1156/0x00000008406c1040@6b8bdcc6

Print the String representation of the anonymous function.

scala> println((_: String) + "sd")
$line10.$read$$iw$$iw$$$Lambda$1158/0x00000008406c3040@31f5b923

Print the String representation of the anonymous function. Save the result in variable b.

scala> val b = println((_: String) + "sd")
$line11.$read$$iw$$iw$$$Lambda$1159/0x00000008406a7040@173cfb01
b: Unit = ()

The print() and println() passed parameter is call-by-reference, not call-by-name, so it is fully evaluated at the call site before being passed to print(). In this case print() receives a function, it doesn't become part of a larger function.

jwvh
  • 50,871
  • 7
  • 38
  • 64