-2

I am curious to understand the datatype of anonymous function in Scala(2.13.8).

While reading Functional programming in Scala, I see below code

scala> (x:Int,y:Int)=> x<y

As per the book, the output should be like below

res3: (Int,Int)=> Boolean = <Function2>

But what I get is

val res3: (Int, Int) => Boolean = $Lambda$883/1341083542@7c871ce4

Below code also does not shows Function2 as type in result

scala> val lessThan = (x:Int,y:Int)=> x<y
val lessThan: (Int, Int) => Boolean = $Lambda$841/566447096@559e3f67

However, When I write the below code, I can see Function2 object is created

scala> val lessThan2 = new Function2[Int,Int,Boolean] {
     | def apply(a:Int, b:Int)= a<b }
val lessThan2: (Int, Int) => Boolean = <function2>

My question is why in an anonymous function, I don't see datatype as Function2(as per the book page number 24, I should have seen it

GPopat
  • 445
  • 4
  • 14
  • 5
    It's just how lambdas are implemeted: each creates its own anonymous class. They are all subclasses of `Function2` though: try `res3.isInstanceOf[Function2[_,_,_]]`, so, it is inconsequential. – Dima Jul 09 '22 at 12:26

2 Answers2

3

Language defines some syntactic sugar which REPL follows:

  • instead of Tuple2(1, 2) you can just do (1, 2)
  • same for Tulple3, Tuple4, etc
  • instead of Function1[Int, String] you can use Int => String
  • same for Function2, Function3, ...

In your example there is also the thing that REPL often shows results int the form

resN: Type: value as seen by toString

Thing is, functions cannot have a reasonable toString representation, so it prints the default JVM toString: name of the class + the instance address. Author of the book simply used <function2> as a placeholder for this seemingly random String which changes for every new function, because it is inconsequential.

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64
  • Not quite. `$Lambda$883/1341083542` is the actual name of a class. Also, functions certainly _can_ have a sensible string representation (for some definition of "sensible" at least): as op shows `new Function2[String,String,Boolean] { def apply(x: String, y: String) = true; }.toString` returns ``, which I am sure some would consider more sensible than `$Lambda$883/1341083542@7c871ce4` (though, personally I would argue that the latter is more informative). – Dima Jul 09 '22 at 13:54
  • 1
    But that's what I said. `$Lambda$883/1341083542@7c871ce4` - `$Lambda$883/1341083542` - name of the class, `@` - separator, `7c871ce4` - hash of the address of the instance. As for whether toString of functions should be overridden... functions cannot be compared, so it'd prefer `toString` to reflect that, sutuation where ` != ` in one case and ` == `in another would be confusing to debug. – Mateusz Kubuszok Jul 09 '22 at 14:19
  • I meant: in practice functions cannot be compared in other way than comparing references. – Mateusz Kubuszok Jul 09 '22 at 14:24
  • 2
    On Scala 2.11 and earlier, it really did print e.g. ``. It's because Scala 2.12 changed to using LambdaMetaFactory, just as Java 8 does, that the `toString` changed. And the book (the first edition) was written well before Scala 2.12 existed. – Seth Tisue Jul 10 '22 at 00:43
  • Thank you all for sharing the knowledge; it's really helpful. what I don't understand is why this question is rated with now -2 :-) – GPopat Jul 11 '22 at 13:52
1

Just to more concretely put what @Dima already hit the nail on the head with:

This is simply a product of the toString implementation of that Lambda instance.


// Note: `(Int, Int) => Boolean` is syntactic sugar for `Function2[Int, Int, Boolean]`

// lessThan: Function2[Int, Int, Boolean]
val lessThan: (Int, Int) => Boolean = { ( x, y ) => x < y }
// $Lambda$16/0x0000000800bb3040@edf4efb

// lessThan.isInstanceOf[Function2[Int, Int, Boolean]]
lessThan.isInstanceOf[(Int, Int) => Boolean]
// True

That is to say the output looks slightly different, but the Lambda instance you created is a sub-class of Function2