How to write efficiently constrained type code when types are not related in Scala
I want to improve on the following Scala code related to Cassandra. I have two unrelated custom types that are actually in Java source files (no details).
public class Blob { .. }
public class Meta { .. }
So, this is how I currently use them from Scala:
private val blobMapper: Mapper[Blob] = mappingManager.mapper(classOf[Blob])
private val metaMapper: Mapper[Meta] = mappingManager.mapper(classOf[Meta])
def save(entity: Object) = {
entity match {
case blob: Blob => blobMapper.saveAsync(blob)
case meta: Meta => metaMapper.saveAsync(meta)
case _ => // exception
}
}
As long as this works, how can you avoid the following problems.
- repetition when adding new user-defined classes such as
Blob
orMeta
- Repeating pattern matching when adding new methods such as
save
- having
Object
as parameter type
source to share
You can definitely use Mapper
as a class by doing:
def save[A](entity: A)(implicit mapper: Mapper[A]) = mapper.saveAsync(entity)
You now have a generic method that can perform a save operation on every type A
for which "23" is in scope.
It is also possible that the implementation mappingManager.mapper
could be improved to avoid classOf
, but it is difficult to tell from the question in its current state.
source to share
A few questions:
- Is it
mappingManager.mapper(cls)
expensive? - How interested are you in handling Blob or Meta subclasses?
Could something like this work for you?
def save[T: Manifest](entity: T) = {
mappingManager.mapper(manifest[T].runtimeClass).saveAsync(entity)
}
If you care about the Meta subclasses capturing the correct mapper, you may find it isAssignableFrom
helpful in your .mapper
(and store the subclasses found in a HashMap, so you only need to look once).
EDIT: Then maybe you want something like this (ignoring threading issues):
private[this] val mapperMap = mutable.HashMap[Class[_], Mapper[_]]()
def save[T: Manifest](entity: T) = {
val cls = manifest[T].runtimeClass
mapperMap.getOrElseUpdate(cls, mappingManager.mapper(cls))
.asInstanceOf[Mapper[T]]
.saveAsync(entity)
}
source to share