Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of elements of compound type

Tags:

scala

I have been playing lately with compound types and I recently was trying the following code:

import scala.reflect._

object Main {

  def main(args: Array[String]) {
    val a1 = classTag[Int with String with Double].newArray(3)
    println(a1.mkString(" "))

    val a2 = classTag[String with Int with Double].newArray(3)
    println(a2.mkString(" "))

    val a3 = classTag[Double with Int with String].newArray(3)
    println(a3.mkString(" "))
  }

}

With the following output:

0 0 0
null null null
0.0 0.0 0.0

It results a bit strange to me. Each of the array elements has access to the methods of the three types: Int, String and Double. What is happening exactly behind scene here? The compound types are actually instances of the first type? Can a compound type being instanced explicitly? Their use case is only for when the types composing the compound are related through inheritance and so on? Thanks.

P.S.: I'm using Scala 2.11.4

like image 471
ale64bit Avatar asked May 16 '26 12:05

ale64bit


1 Answers

What is happening exactly behind scene here? The compound types are actually instances of the first type?

Looking at the newArray method as defined for ClassTag:

override def newArray(len: Int): Array[T] =
   runtimeClass match {
     case java.lang.Byte.TYPE      => new Array[Byte](len).asInstanceOf[Array[T]]
     case java.lang.Integer.TYPE   => new Array[Int](len).asInstanceOf[Array[T]]
     /* snip */
     case _                        => java.lang.reflect.Array.newInstance(runtimeClass, len).asInstanceOf[Array[T]]
   }

And then your type:

scala> classTag[Int with String with Double].runtimeClass
res4: Class[_] = int

It seems pretty clear how it's arriving at the conclusion to use the first type. The runtimeClass of Int with String with Double is Int, and the newArray method uses the runtimeClass to construct the new Array. So the Array is filled with default Int values. Likewise for the other order combinations.

Why is the runtime class Int? Well, Int with String with Double isn't an actual class, but Int is. The compiler's choice of which class to use can't just be arbitrary, so why not the first?

Can a compound type be instanced explicitly?

I'm not sure what you mean by this. If you think about it, the compiler kind of has to favor one type in this composition. What would an explicit Int with String with Double look like? What about Int with String with Double with Product with Process ? I don't know, either.

Each of the array elements has access to the methods of the three types: Int, String and Double

They do, and yet they don't.

scala> val arr = classTag[Int with Process].newArray(3)
arr: Array[Int with Process] = Array(0, 0, 0)

scala> arr(0).exitValue()
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Process

You're really just tricking the compiler into believing you have an Array of these types, when in fact you don't (and can't, because nothing can be a sub-type of both Int and Process).

Their use case is only for when the types composing the compound are related through inheritance and so on?

Pretty much, yes. I can't think if any situation in which you'd ever want to try to build these types directly. Their main use case is to guarantee that a type inherits from other specific types.

For example, a method that requires that a parameter inherit methods from two traits:

trait Hello { def hello = println("Hello") }

trait Bye { def bye = println("Bye") }

def greet(hb: Hello with Bye): Unit = { hb.hello; hb.bye }

class A extends Hello

class B extends Hello with Bye

scala> greet(new A)
<console>:15: error: type mismatch;
  found   : A
  required: Hello with Bye
          greet(new A)
                ^

scala> greet(new B)
Hello
Bye
like image 139
Michael Zajac Avatar answered May 19 '26 03:05

Michael Zajac



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!