Question

I'm reflectively invoking a method whose argument might or might not be an instance of a value class. As the purpose of value classes is to avoid boxing of underlying value, if the parameter type is value class then the method in question will in fact expect unboxed value. To handle this case I'm trying to unwrap the underlying value from value class. I first need to determine if the argument is of a value class, and here I hit the first stumbling block:

def isObjectOfValueClass(arg: Any) = 
  classOf[AnyVal].isAssignableFrom(arg.getClass)

This doesn't work as expected, as the method returns true for:

case class NonValueClass(underlying: Int)

How can isObjectOfValueClass be implemented? Or is there a simpler way to reflectively invoke a method that might take object of a value class as an argument?

Was it helpful?

Solution

First, note that your isObjectOfValueClass will get a boxed version of your value class instances.

Second, it cannot work like you want. It's because classOf[AnyVal] == classOf[AnyRef] == <java.lang.Object>.

There's no runtime way to distinguish between a boxed value class and a reference class (Any doesn't have .instanceOf[T], AnyVal cannot be used in pattern matching or as parameter of .instanceOf[T], and what's most important, compiled value classes do not extend or implement AnyVal).

If you want it decided on compile time, then try:

case class IsAnyVal[-T](val value: Boolean) extends AnyVal 
implicit def _noClueHowToNameThisImplicit_1 = IsAnyVal[AnyVal](true)
implicit def _noClueHowToNameThisImplicit_2 = IsAnyVal[AnyRef](false)
def isAnyVal[T](arg: T)(implicit ev: IsAnyVal[T]) = ev.value

scala> isAnyVal(1)
res4: Boolean = true

scala> isAnyVal("")
res5: Boolean = false

I'm not sure how you want to extract the sole field of the detected boxed value class instances without more accidental boxing. Besides, Hotspot is pretty good at optimizing small short-lived objects.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top