Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the runtime Class of a parameterized Type in a Scala trait

Tags:

scala

I'm trying to implement a Scala trait that handles the details of interfacing with a Java library that requires us to create

What I want to do is something like:

trait SomeTrait[A] extends JavaAPI {
  def foo = {
    callApi(classOf[A])
  }

  override def bar = {
    foo
  }
}

Note that bar is actually overriding a method from a base class, so I can't change it's signature.

I've tried several variations with Manifests, etc., but can't quite get this to work. Is there a way to get the runtime class of a parameterized type?

like image 382
John Stauffer Avatar asked Dec 13 '10 21:12

John Stauffer


People also ask

Can a scala trait take parameters?

Unlike a class, Scala traits cannot be instantiated and have no arguments or parameters. However, you can inherit (extend) them using classes and objects.

Can scala traits have methods?

In scala, trait is a collection of abstract and non-abstract methods. You can create trait that can have all abstract methods or some abstract and some non-abstract methods. A variable that is declared either by using val or var keyword in a trait get internally implemented in the class that implements the trait.

Can scala trait have constructor?

In Scala, we are allowed to implement the method(only abstract methods) in traits. If a trait contains method implementation, then the class which extends this trait need not implement the method which already implemented in a trait. As shown in the below example. Traits does not contain constructor parameters.

Can object extends trait scala?

Traits are used to share interfaces and fields between classes. They are similar to Java 8's interfaces. Classes and objects can extend traits, but traits cannot be instantiated and therefore have no parameters.


2 Answers

This flavour should do the trick:

trait SomeTrait[A] {
  def foo(implicit ev: Manifest[A]) = {
    callApi(ev.erasure)
  }
}

update At some point, the manifest must be injected via a method parameter. A constructor would be a good choice, if traits could have them.

Actually, they can! The trait has the constructor of whatever it's mixed-in to, so if you specify an abstract manifest that deriving classes must define...

trait SomeTrait {
  def ev: Manifest[_] //abstract
  def foo = println(ev.erasure)
}

//this `ev` provides the implementation, note that it MUST be a val, or var
class Concrete[T](implicit val ev: Manifest[T]) extends SomeTrait

And all is good again.

like image 192
Kevin Wright Avatar answered Oct 27 '22 22:10

Kevin Wright


You have to get the manifest in there somehow, and traits have no constructor parameters. Only you can say what tradeoff you want to make. Here's another one.

trait SomeTrait[A] {
  implicit def manifesto: Manifest[A]

  def foo = println(manifest[A].erasure)
}
object SomeTrait {
  def apply[A: Manifest] : SomeTrait[A] = new SomeTrait[A] { def manifesto = manifest[A] }
}
like image 30
psp Avatar answered Oct 27 '22 22:10

psp