Why 'val arr: Int => Int = Array(1,2,3)' is allowed in scala

Viewed 113

With the following code:

object Foo {
  val arr: Int => Int = Array(1,2,3)  
}

We can call Foo.arr(1), then get 2. However, arr in object Foo should be a Function. The arr is an instance of Class WrappedArray$ofInt, which is obviously not a Function.
I guess maybe the reason is WrappedArray$ofIntimplements apply(i: Int), because the call Array(1,2,3)(1) will be translated into Array(1,2,3).apply(1). But the following code would be error:

class Bar {
  def apply(i: Int): Int = {
    Array(1,2,3)(i)
  }
}
object Foo {
  val arr: Int => Int = new Bar()  //Type mismatch: 
                                   //    Required: Int => Int 
                                   //    Found: Bar
}

Now, why val arr: Int => Int = Array(1,2,3) is allowed in scala?

1 Answers

The REPL is an amazing tool to explore these kinds of situations.

So, let's start with the code:

val arr: Int => Int = Array(1,2,3)

In Scala the only way this would work is if Array[Int] <: Int => Int or if there would be an implicit conversion from Array[Int] into something that is a subtype of Int => Int

We can check that the first one is not the case quite easily:

implicitly[Array[Int] <:< Int => Int]}

Which produces:

error: No implicit view available from Array[Int] <:< Int => Int.

Thus, it has to be the second one; and we may also confirm it doing:

implicitly[Array[Int] => (Int => Int)]
// val res: Array[Int] => (Int => Int) = $Lambda$1165/0x00000008406ff040@4dac40b

BTW, if we paste the original line in the REPL we get the following output:

val foo: Int => Int = Array(1,2,3)
// val foo: Int => Int = ArraySeq(1, 2, 3)

So we can already see that the conversion took place and that the result is an ArraySeq[Int] (and if you check the Scaladoc you can see that class does indeed inherit Int => Int).


If you want to dive even deeper you can use reify

import scala.reflect.runtime.universe.reify

reify { val foo: Int => Int = Array(1,2,3) }

Which produces the following output:

val res: reflect.runtime.universe.Expr[Unit] =
Expr[Unit]({
  val foo: Function1[Int, Int] = Predef.wrapIntArray(Array.apply(1, 2, 3));
  ()
})

And following the docs again we can see that it indeed returns an ArraySeq.

Related