1

By assigning a variable (or value?) a method name with a space and an underscore, you tell scala to treat the method as a function, which apparently means doing more than simply taking the value generated by a call to the method and assigning to the variable. What else is/can go on through such an assignment?

  • 2
    `foo _` is more like *package method foo into value* – om-nom-nom Apr 21 '15 at 13:05
  • 1
    possible duplicate of classic [Difference between method and function in Scala](http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala) – dk14 Apr 21 '15 at 14:13

3 Answers3

4

Since Scala runs on the JVM, it's easier to understand in terms of simple Java-like classes without Scala's syntactic sugar.

Remember that Scala functions are essentially members of a class similar to the following (signature deliberately simplified):

class Function[X, Y] {
  def apply(x: X): Y
}

Application of a function f to an argument x is desugared into a method application f.apply(x).

Now suppose that you have another class Foo with method bar:

class Foo {
  def bar(x: Int): String
}

If you now have an instance foo of type Foo, then whenever its method bar is transformed into a function by writing:

val f = foo.bar(_)

a new instance of an anonymous subclass of Function is created:

val f = new Function[Int, String] {
  def apply(x: Int) = foo.bar(x)
}

If you use this syntax inside a class, this is closed over instead of an instance foo.

This is what all those weirdly named classes Main$$anon$1$$anonfun$1 are: they are the anonymous classes that represent functions. The functions can appear quite implicitly (for example, as blocks passed to the for-loops).

That's all there is to it semantically. The rest is just syntactic sugar.

Here is a complete runnable example that demonstrates the conversion of an instance method into a function:

  1. with sugar, from the outside (a)
  2. with sugar, from the inside (b)
  3. without sugar, from the outside (c)
  4. without sugar, from the inside (d)

You can save it into a file and execute with scala <filename.scala>:

/** A simple greeter that prints 'hello name' multiple times */
case class Hey(name: String) { thisHeyInst =>
  def hello(x: Int): String = ("hello " + name + " ") * x
  def withSugarFromInside = hello(_)
  def noSugarFromInside = new Function[Int, String] {
    def apply(y: Int) = thisHeyInst.hello(y)
  }
}

val heyAlice = Hey("Alice")
val heyBob = Hey("Bob")
val heyCharlie = Hey("Charlie")
val heyDonald = Hey("Donald")

val a = heyAlice.hello(_)
val b = heyBob.withSugarFromInside
val c = new Function[Int, String] { def apply(y: Int) = heyCharlie.hello(y) }
val d = heyDonald.noSugarFromInside

println(a(3))
println(b(3))
println(c(3))
println(d(3))

In all four cases, a greeting is printed three times.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
1

What _ actually does is an eta-conversion. It takes compile-time construction called method and returns runtime construction called anonymous function, which is actually an instance of scala's Function. Exactly the class depends on arity, so it might be Function1, Function2, Function3 and so on. The point here is to make First-class citizen, which may act like a value.

OOP needs a little more than some new object. Before making the code that creates instance, compiler generates a new class (extending FunctionN) in compile-time, but theoretically it shouldn't be necessary a whole new class. For Java 8 it could be native Java-lambdas.

Btw, you may extend Function1 by yourself and even eta-abstract it again:

 scala> object f extends (Int => Int) { def apply(a: Int) = a }
 scala> f(1)
 res0: Int = 1

 scala> f.apply _
 res1: Int => Int = <function1>

 scala> res1(5)
 res2: Int = 5

As a conclusion a little copy-paste from @Daniel C. Sobral's answer:

the former can be easily converted into the latter:

val f = m _

Scala will expand that, assuming m type is (List[Int])AnyRef into (Scala 2.7):

val f = new AnyRef with Function1[List[Int], AnyRef] {
  def apply(x$1: List[Int]) = this.m(x$1)
}

On Scala 2.8, it actually uses an AbstractFunction1 class to reduce class sizes.

Or simply saying val f = m _ is same as val f = (x: List[Int]) => m(x)

To make this answer more modern and precise let's see what's happening using scalac 2.11.2 and javap:

$ echo "object Z{def f(a: Int) = a}" > Z.scala //no eta-abstraction here

$ scalac Z.scala

$ ls
Z$.class    Z.class     Z.scala

$ echo "object Z{def f(a: Int) = a; val k = f _}" > Z.scala

$ scalac Z.scala

$ ls
Z$$anonfun$1.class  Z.class //new anonfun class added for lambda
Z$.class        Z.scala

$ javap -c Z\$\$anonfun\$1.class 
Compiled from "Z.scala" // I've simplified output a bit
public final class Z$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp implements scala.Serializable {

  public final int apply(int);
    Code:
      calling apply$mcII$sp(int)

  public int apply$mcII$sp(int); //that's it
    Code:
       0: getstatic     #25    // reading Field Z$.MODULE$:LZ$;, which points to `object Z`
       3: iload_1       
       4: invokevirtual #28    // calling Method Z$.f
       7: ireturn       

  public final java.lang.Object apply(java.lang.Object); //just boxed version of `apply`
    Code:

      unboxToInt
      calling apply(int) method
      boxToInteger       

  public Z$$anonfun$1();
    Code:
      AbstractFunction1$mcII$sp."<init>":()V //initialize

}

So it still extends AbstractFunction1

Community
  • 1
  • 1
dk14
  • 22,206
  • 4
  • 51
  • 88
0

I'll try to provide some examples how a function or method are assigned to values with underscore.

If it's need to reference a zero-argument function

scala> val uuid = java.util.UUID.randomUUID _
uuid: () => java.util.UUID = <function0>

scala> uuid()
res15: java.util.UUID = 3057ef51-8407-44c8-a09e-e2f4396f566e

scala> uuid()
uuid: java.util.UUID = c1e934e4-e722-4279-8a86-004fed8b9090

Check how it's different when one does

scala> val uuid = java.util.UUID.randomUUID
uuid: java.util.UUID = 292708cb-14dc-4ace-a56b-4ed80d7ccfc7

In first case one assigned a reference to a function. And then calling uuid() generates new UUID every time. In second, function randomUUID has been called and value assigned to a val uuid.

There are some other cases why _ might be useful. It's possible to use a function with two arguments and create a function with a single argument out of it.

scala> def multiply(n: Int)(m: Int) = n*m
multiply: (n: Int)(m: Int)Int

scala> val by2 = multiply(2) _
by2: Int => Int = <function1>

scala> by2(3)
res16: Int = 6  

To be able to do, it's crucial to define function multiply as curried. It's called function currying.

Ivan Stanislavciuc
  • 7,140
  • 15
  • 18