reyman64
reyman64

Reputation: 553

Casting after comparison of two Array manifest in scala

I have some problem to cast my objeсt Variable[A] where A <: Array[_]

I create a function to compare manifest and cast data into Array to the good type.

My object Variable[A] store a Manifest[A] into the def 'type'

I make a plugin of an existent software, so it's not me which instanciate this Variable with good type.

Prototype object and class :

object Prototype {
  def apply[T](n: String)(implicit t: Manifest[T]) = new Prototype[T] {
    val name = n
    val `type` = t
  }
}

trait Prototype[T] {
  def name: String
  def `type`: Manifest[T]
}

Variable Object and Class :

object Variable {
  def apply[T](p: Prototype[T], v: T) = new Variable[T] {
    val prototype = p
    val value = v
  }
}

trait Variable[T] {
  def prototype: Prototype[T]
  def value: T
}

My class which use :

class XYDataReader[A <: Array[_]](var data: Iterable[Variable[A]]) {

    def get[T](variable: Variable[A])(implicit m: Manifest[T]): Option[T] = {
        if (variable.prototype.`type` <:< m) {
          Some(variable.value.asInstanceOf[T])
        } else {
          None
        } 
}
}

There is probably a mistake of my part when i instanciate Variable object used to compare, so i give also the code of instanciation :

val v:List[Any] = List[Any](1.2,2,3)
val p = Prototype[Array[Any]]("col1")
val myVariable = Variable(p, v.toArray(ClassTag(p.`type`.runtimeClass)))

I don't understand why pattern matching failed when i call get[Array[Double]](myVariable) where myVariable.value contain an Array[Double]

When i println() the two manifest :

It seem an Array[Double] is not an Array[double], how can i resolve/cast this ?

Upvotes: 1

Views: 216

Answers (2)

reyman64
reyman64

Reputation: 553

Finally, with help of colleague methods to resursively unArrayify Array, i resolve my runtime type reification problem. Now i can compare equality between Array[double] with Array[Double].

  // Convert unknow A en Array[T], so you need to call get with Type :
  // example : get[Array[Double](myVariable)
  // return an Array[Double] only if it's possible for this Variable, else it return None
  def get[T](variable: Variable[A])(implicit m: Manifest[T]): Option[T] = {
    if (ClassUtils.assignable(variable.prototype.`type`.runtimeClass, m.runtimeClass)) {
      val casted = variable.prototype.`type`.runtimeClass.cast(variable.value)
      Some(casted.asInstanceOf[T])
    } else {
      None
    }

I hope these methods can help other people :)

You can see helping method ClassUtils.assignable here :

https://gist.github.com/4686167

and on the source forge project :

https://forge.iscpif.fr/projects/openmole/repository/revisions/master/entry/core/openmole/misc/org.openmole.misc.tools/src/main/scala/org/openmole/misc/tools/obj/ClassUtils.scala

Upvotes: 0

Randall Schulz
Randall Schulz

Reputation: 26486

This started out as a comment, since it's not an answer, but it's too big and needs formatting (plus my browser tab's auto-reload caused it to be lost the first time...)

So... For starters, your snippet of code is incomplete and / or incorrect. Potentially there are imports in effect which could alter the meaning of that code. Secondly, as shown it would not compile 'cause what appears to be a formal type parameter, the A has no binding. Thus unless you have an actual type named A that won't compile.

Secondly, Double is potentially ambiguous. There is both scala.Double and java.lang.Double and they are distinct. Scala auto-boxes and -unboxes primitive types for you, typically when they're used to instantiate type parameters for generic methods (and specialization is not used). A consequence of this is that Array[scala.Double] is distinct from Array[java.lang.Double]. Scala will create arrays of primitive types when possible, but Array[java.lang.Double] is explicitly an array of boxed double-precision floating point.

E.g.:

scala> val d1: scala.Double = 123.456
d1: Double = 123.456

scala> val d2: java.lang.Double = 234.567
d2: Double = 234.567

scala> d1.getClass
res25: Class[Double] = double

scala> d2.getClass
res26: Class[_ <: Double] = class java.lang.Double

scala> val ad1: Array[scala.Double] = Array(123.456, 234.567)
ad1: Array[Double] = Array(123.456, 234.567)

scala> val ad2: Array[java.lang.Double] = Array(234.567, 345.678)
ad2: Array[Double] = Array(234.567, 345.678)

scala> ad1.getClass
res27: Class[_ <: Array[Double]] = class [D

scala> ad2.getClass
res28: Class[_ <: Array[Double]] = class [Ljava.lang.Double;

So please, if you would, fill in the missing details of your sample code?

Upvotes: 1

Related Questions