Pattern matching with manifest instances of a private class

Given classes

sealed abstract class A case class B(param: String) extends A case class C(param: Int) extends A trait Z {} class Z1 extends Z {} class Z2 extends Z {} def zFor[T <: A : Manifest]: Option[Z] = { val z = manifest[T].erasure if (z == classOf[B]) { Some(new Z1) } else if (z == classOf[C]) { Some(new Z2) } else { None } } 

I think the problem with pattern matching here is the inability to build a pattern matching table in bytecode. Is there any solution to this problem? Maybe I can use some Int generated in the Manifest compiler?

+4
source share
2 answers

The way you wrote it is not very reliable if you have a more complex class hierarchy, because if you have a class D <: C , then classOf[D] != classOf[C] . So you still don't want the pattern to match. But you could; you cannot call classOf[X] in the middle of matching the pattern, but you can

 def zFor[T <: A : Manifest]: Option[Z] = { val ClassB = classOf[B] val ClassC = classOf[C] manifest[T].erasure match { case ClassB => Some(new Z1) case ClassC => Some(new Z2) case _ => None } } 

while you are sure that you are in a situation where you only need to discover the leaves of the class hierarchy. (You should probably make sure by noting B and C final .)

Alternatively, you can use isAssignableFrom to run a run-time test:

 def zFor2[T <: A : Manifest]: Option[Z] = { manifest[T].erasure match { case x if classOf[B].isAssignableFrom(x) => Some(new Z1) case x if classOf[C].isAssignableFrom(x) => Some(new Z2) case _ => None } } 

and now

 class D extends C(5) {} scala> zFor[D] res5: Option[Z] = None scala> zFor2[D] res6: Option[Z] = Some( Z2@2556af33 ) 
+2
source

I'm not sure if this fits your problem (as you probably showed a simplified example). But such functionality can be created without using reflection.

This is a fairly common pattern that allows you to create additional combinations without changing the source code.

 // the - here allows D to return the instance for C // if you only want exact matches, remove the - trait GetZ[-X] { type Out def z: Option[Out] } trait LowerPriority { implicit def noZ[A] = new GetZ[A] { type Out = Nothing val z = None } } object GetZ extends LowerPriority { implicit def forB = new GetZ[B] { type Out = Z1 def z = Some(new Z1) } implicit def forC = new GetZ[C] { type Out = Z2 def z = Some(new Z2) } } def zFor[T](implicit getZ: GetZ[T]): Option[getZ.Out] = getZ.z 

Using

 class D extends C(5) val noZ = zFor[A] val Some(z1) = zFor[B] val Some(z2) = zFor[C] val Some(other_z2) = zFor[D] 
+1
source

Source: https://habr.com/ru/post/1481572/


All Articles