diplosaurus
diplosaurus

Reputation: 2588

Function literals vs function values

Trying to figure out the significance of this section from Programming in Scala, 2nd edition.

A function literal is compiled into a class that when instantiated at run- time is a function value. Thus the distinction between function literals and values is that function literals exist in the source code, whereas function val- ues exist as objects at runtime. The distinction is much like that between classes (source code) and objects (runtime).

I don't really get what they're trying to say here. That function values don't exist in the source code and function literals don't exist at runtime?

// literal
val addOne = (x: Int) => x + 1

// value
def add1(x: Int): Int = x + 1

I can pass either to another function:

def doThing(thing: Int => Int) = thing(5)

doThing(addOne) // 6
doThing(add1)   // 6

It also appears that function literals are placed into a class that inherits from FunctionN (where N is the arity of the function). What distinction are they trying to make here?

Upvotes: 6

Views: 1184

Answers (3)

Jörg W Mittag
Jörg W Mittag

Reputation: 369420

There's nothing special about functions in that paragraph. It applies exactly the same to other kinds of literals, e.g. integers.

  • The specific character sequence composed of the character with the ASCII value 0x34 followed by the character with the ASCII value 0x32 and surrounded by whitespace, parentheses, comma, semicolon, or some other kind of delimiter, is an integer literal.
  • It will be compiled into an instance of the Int class. (Actually, that's not quite true: on the JVM implementation of Scala, it will be compiled into a JVM primitive int, and on the ECMAScript implementation of Scala, it will be compiled into an ECMAScript Number, and the compiler will generate additional code to "fake" it being an instance of the scala.Int class.)
  • At runtime, it will be instantiated into an integer representing the value 42.

Functions are no different here. The specific sequence of characters that make up a literal (whether that be a function literal, integer literal, string literal, character literal, symbol literal, tuple literal, boolean literal, or the literal value null) exist only in the source code. The values those literals represent exist only at runtime. The compile time representation of those literals is as an instance of some class.

Upvotes: 0

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149518

I don't really get what they're trying to say here.

Your example of a function literal and value aren't accurate. The book is not comparing methods to functions, it's creating a distinction between two different "modes" of a function. The hint is in the first sentence:

A function literal is compiled into a class that when instantiated at run-time is a function value.

When at compile time you type:

val addOne = (x: Int) => x + 1

This is what the book refers to as a "function literal" (or Anonymous Function). The same way you have a string literal by typing:

val s = "Hello, World"

addOne to the compiler is a Function1[Int, Int], meaning takes an Int and returns an Int result. The function literal syntax ((x: Int) => x + 1) is syntactic sugar over FunctionN, where N is determined by the arity of the function.

At run-time, the compiler takes this "function literal" and "puts life into it" by instantiating an object of type Function1[Int, Int], thus creating a function value which you can invoke, pass around, etc.

What distinction are they trying to make here?

The book is basically trying to create a distinction between the compile time and runtime representation of a function, so when they say "function literal" you'll understand they're talking about the former, and when they say "function value" the latter.

Upvotes: 4

ka4eli
ka4eli

Reputation: 5424

Scala code compiles into jvm bytecode which does not have functions but has classes. So your code val addOne = (x: Int) => x + 1 is syntactic sugar for (I'm not precise here, only high concepts):

final class anonFun extends scala.runtime.AbstractFunction1 {
    final def apply(x: Int) = x + 1
}

val addOne = new anonFun();

Actually compiled files are much more complex, you can compile your scala file with scalac -print and see desugared scala code. Here is my compile output of small object:

object Main {
  val addOne = (x: Int) => x + 1
}

(scalac version 2.11.7)

package <empty> {
  object Main extends Object {
    private[this] val addOne: Function1 = _;
    <stable> <accessor> def addOne(): Function1 = Main.this.addOne;
    def <init>(): Main.type = {
      Main.super.<init>();
      Main.this.addOne = {
        (new <$anon: Function1>(): Function1)
      };
      ()
    }
  };
  @SerialVersionUID(value = 0) final <synthetic> class anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
    final def apply(x: Int): Int = anonfun$1.this.apply$mcII$sp(x);
    <specialized> def apply$mcII$sp(x: Int): Int = x.+(1);
    final <bridge> <artifact> def apply(v1: Object): Object = scala.Int.box(anonfun$1.this.apply(scala.Int.unbox(v1)));
    def <init>(): <$anon: Function1> = {
      anonfun$1.super.<init>();
      ()
    }
  }
}

At the contrast look at compiling

object Main {
    def addOne(i: Int) = i + 1
}

(scalac version 2.11.7)

package <empty> {
  object Main extends Object {
    def addOne(i: Int): Int = i.+(1);
    def <init>(): Main.type = {
      Main.super.<init>();
      ()
    }
  }
}

You can see that def addOne becomes just an instance method of an object, but val addOne is itself an object.

Upvotes: 3

Related Questions