Let's say I have a specialized class and an associated companion object:
trait Slice[@specialized +T] { ... override def equals(that :Any) = that match { case s :Slice[_] => ??? case _ => false } } object Slice { def newInstance[@specialized T] = ??? }
Is there any way to check
- Inside a method of Slice if this instance is a specialized subclass,
- Inside a method of Slice if another instance is a specialized subclass for the same primitive,
- Inside a specialized method on a companion object if I'm running an erased or specialized variant
without resorting to ClassTags or passing Class[_] manually? It seems like that information should be available, but the only way I can think of involves checking names of the classes.
Use case 2) is particularly important, as I could resort to faster algorithms if I new I'm comparing apples with apples. It probably could be accomplished by reflection, but it would be quite tricky when you take into account that we have to handle non-synthetic subclasses of Slice, too; if we have also
trait ArraySlice[@specialized T] extends Slice[T] { ... }
that should be considered 'compatible' with Slice[T] instances as long as they are both specialized (or both erased)?
Ok, I figured out a cleaner way:
final val AllButUnit = new Specializable.Group((Byte, Short, Int, Long, Char, Float, Double, Boolean, AnyRef)) def specializationFor[@specialized(AllButUnit) E] :ResolvedSpecialization[E] = Specializations(new SpecializedKey[E]).asInstanceOf[ResolvedSpecialization[E]] private val Specializations = Seq( resolve[Byte], resolve[Short], resolve[Int], resolve[Long], resolve[Char], resolve[Float], resolve[Double], resolve[Boolean], resolve[Unit], resolve[AnyRef] ).map( spec => spec.key -> spec :(SpecializedKey[_], ResolvedSpecialization[_]) ).toMap.withDefaultValue(resolve[AnyRef]) private def resolve[@specialized(AllButUnit) E :ClassTag] :ResolvedSpecialization[E] = new ResolvedSpecialization[E](new SpecializedKey[E], new Array[E](0)) class ResolvedSpecialization[@specialized(AllButUnit) E] private[SpecializedCompanion] (val array :Array[E], val elementType :Class[E], val classTag :ClassTag[E], private[SpecializedCompanion] val key :SpecializedKey[E]) { private[SpecializedCompanion] def this(key :SpecializedKey[E], array :Array[E]) = this(array, array.getClass.getComponentType.asInstanceOf[Class[E]], ClassTag(array.getClass.getComponentType.asInstanceOf[Class[E]]), key) override def toString = s"@specialized($elementType)" override def equals(that :Any) = that match { case r :ResolvedSpecialization[_] => r.elementType==elementType case _ => false } override def hashCode = elementType.hashCode } private class SpecializedKey[@specialized(AllButUnit) E] { override def equals(that :Any) = that.getClass==getClass override def hashCode = getClass.hashCode def className = getClass.getName override def toString = className.substring(className.indexOf("$")+1) }
Now specializationFor[E].elementType returns class corresponding to specialization parameter of E.