Array of complex type elements
I have been playing around with composite types lately and I recently tried using 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
This is a little strange to me. Each of the array elements has access to three types of methods: Int, String, and Double. What is happening behind the scenes here? Are the constituent types actually instances of the first type? Can an explicit composite type? Does their use only happen when the types that make up the connection are related through inheritance and so on? Thank.
PS: I am using Scala 2.11.4
source to share
What is happening behind the scenes here? Connection types are instances of the first type?
Looking at the method newArray
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 he comes to the conclusion to use the first type. runtimeClass
of Int with String with Double
- Int
, and the method newArray
uses runtimeClass
to create a new one Array
. Thus, it is Array
populated with default values Int
. Likewise for other combinations of orders.
Why an execution class Int
? Well, Int with String with Double
not an actual class, but it Int
is. The compiler's choice of which class to use cannot be arbitrary, so why not the first one?
Can a composite type be explicitly specified?
I'm not sure what you mean by that. If you think about it, then the compiler should use one type in this composition. What does explicit look like Int with String with Double
? What about Int with String with Double with Product with Process
? I do not know either.
Each of the array elements has access to methods of 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 really just cheating the compiler, assuming that you have Array
these types, when in fact you do not (and can not, because nothing can be a subtype of both Int
, and so Process
).
Does their use only happen when the types that make up the connection are related through inheritance, etc.?
To a large extent, yes. I can't think if there is any situation in which you would ever want to try to construct these types directly. Their main use case is to ensure that a type inherits from other concrete types.
For example, a method that requires a parameter to 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
source to share