5

Can someone explain the following to me:

scala> def squared(x: Int) = x * x
squared: (x: Int)Int
scala> val sq : (Int) => Int = squared
sq: Int => Int = <function1>
scala>  sq.getClass
res111: Class[_ <: Int => Int] = class $anonfun$1

I understand this so far, squared is a function while sq is a function pointer.

But then I do this:

scala> squared.getClass
<console>:13: error: missing arguments for method squared;
follow this method with `_' if you want to treat it as a partially applied function
   squared.getClass
   ^

Why can't I invoke getClass on squared ? After all, aren't functions 1st class objects ? Why do I need to do this for it to work ?

scala> squared(7).getClass
res113: Class[Int] = int

And I also get the same result for

scala> sq(5).getClass
res115: Class[Int] = int

Come to think of it, why do

scala>squared(5)

and

scala> sq(5)

produce the same result, even though one is a function, and the other a function pointer without needing to use a different syntax ? Something akin to *sq(5) may have been clearer, no ?

femibyte
  • 3,317
  • 7
  • 34
  • 59
  • I believe it has to do with def vs val. Def evaluates when called, val when defined. This might have more info: http://stackoverflow.com/questions/18887264/what-is-the-difference-between-def-and-val-to-define-a-function – Robert Horvick May 21 '16 at 23:28

2 Answers2

11

The concept of a pointer isn't really relevant here, or in Scala (or the JVM) more generally. The difference between squared and sq is that squared is a method, and sq is a function.

Scala is (primarily) a language designed to be compiled to JVM bytecode. The JVM doesn't have first class functions, but it does have methods, which are associated either with an instance of a class (instance methods) or simply with the class itself (static methods). Methods in this sense are a fundamentally different kind of thing than objects to the JVM—they can't be passed as arguments to other methods, etc.

Because Scala is a functional language and functional languages are built on the idea of higher-order functions and first class functions more generally, the Scala language designers needed to be able to encode functions in a way that would work on the JVM. This is done via a Function1 class, and when you write something like this:

val sq: (Int) => Int = x => x * x

You are using Scala's syntactic sugar for creating instances of the Function1 class. These things are functions encoded as JVM objects, so they can be passed around and treated as first class things in the language.

Scala doesn't abandon the idea of methods, though. For reasons related in part to Scala's functional-OOP hybridity and in part to issues of performance, most Scala programs make extensive use of def definitions, which define methods, not "functions" in the sense of Function1. Scala provides a special conversion process (called eta expansion) by which methods can be treated as functions in many situations (including the right-hand side of your sq definition here).

If this all seems confusing, believe me, it is. You get used to it after a while, though (just get the idea of pointers out of your head as quickly as possible).

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
4

I understand this so far, squared is a function while sq is a function pointer.

Incorrect. Scala has neither explicit pointers nor function pointers

scala> (squared _).getClass
res4: Class[_ <: Int => Int] = class $anonfun$1

scala> sq.getClass
res5: Class[_ <: Int => Int] = class $anonfun$1

scala> :type squared _
Int => Int

scala> :type sq
Int => Int

Both have the same type. The difference is that functions which are defd do not live in the same namespace as vals or vars and code which refers to one is parsed differently from code which refers to the other.

Specifically, a reference to a val is an expression which can be evaluated. A reference to a defd function is not an expression and you can't apply operators like . which only apply to values.

Marcin
  • 48,559
  • 18
  • 128
  • 201
  • `squared` doesn't really have the same type as `sq`, because `squared` doesn't have a type in this sense at all—it's not an expression. You can write `:type squared _` only because you're explicitly eta-expanding it with the `_`. – Travis Brown May 21 '16 at 23:52
  • @TravisBrown Correct. That is what I say in my final paragraph. – Marcin May 21 '16 at 23:57