Is it possible to get the type name of a generic class in Scala? I know this isn't possible in Java with type erasure, but I was hoping that Scala would be a different case.
Currently I have to do something similar to this:
trait Model
case class User(id: String) extends Model
def fromMap[M<:Model : Manifest](data: Map[String, String], modelType: String) = {
modelType match {
case "user" => User(data.get("id").get)
}
}
val user = fromMap[User](Map("id" -> "id1"), "user")
Obviously it would be easier if I could work out "user" without having to have it passed in.
You can see that in the main method, or in any instance method, I am capable to get the name of the generics type, in this case the main will print: java. lang. Integer. ...and you get the name of the subclass (if any).
In Scala, forming a Generic Class is extremely analogous to the forming of generic classes in Java. The classes that takes a type just like a parameter are known to be Generic Classes in Scala. This classes takes a type like a parameter inside the square brackets i.e, [ ].
Language. Methods in Scala can be parameterized by type as well as value. The syntax is similar to that of generic classes. Type parameters are enclosed in square brackets, while value parameters are enclosed in parentheses.
A Generic class simply means that the items or functions in that class can be generalized with the parameter(example T) to specify that we can add any type as a parameter in place of T like Integer, Character, String, Double or any other user-defined type.
Class name can be retrieved from a Manifest (or a ClassManifest) with manifest.erasure.getName
(erasure is the Class instance). For instance
def className[A : ClassManifest] = classManifest[A].erasure.getName
Edit : Seen Derek's answer, which makes this stuff with erasure.getName look rather stupid. I didn't consider toString. Still I hope what follows may be of interest
The difference between using ClassManifest
and Manifest
is that in the Manifest
for a generic class, the type parameter are guaranteed to be available, while they are best effort in ClassManifest
(compare signatures of typeParameters
in both classes). The drawback of this guarantee is that a Manifest
might not be implicitly available where a ClassManifest
would be.
Have you considered using typeclasses instead?
trait BuilderFromMap[A] {def build(data: Map[String, String]): A}
// or better, return Option[A], accounting for possible failure
object User {
implicit val Builder extends BuilderFromMap[User] {...}
}
def fromMap[A](data: Map[String, String])(implicit builder: BuilderFromMap[A])
= builder.build(data)
This way, calls to fromMap
will compile only if a Builder
is available for this particular class, rather than fail with a MatchError
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With