Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the specific simple name of a generic type in Scala

Tags:

generics

scala

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.

like image 698
Ben Smith Avatar asked Aug 24 '11 12:08

Ben Smith


People also ask

How do I find my generic class name?

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).

What is generic type in Scala?

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, [ ].

What is type parameter in Scala?

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.

How do you define a generic class?

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.


1 Answers

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.

like image 107
Didier Dupont Avatar answered Oct 03 '22 02:10

Didier Dupont