Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala trait runtime class from type parameter

I have a scala trait [this trait does not compile]

trait MyTrait[T <: Enum] {
  def myMethod(name: String): T = {
    MyJavaClass.staticMethod(name, classOf[T])
  }
}

And a Java class

public class MyJavaClass {
    public static <T extends Enum> T staticMethod(String name, Class<T> c) {
        return (T) T.valueOf(c, name);
    }
}

How can I make the trait valid scala? What I'm currently doing is adding a Class[T] field like this

trait MyTrait[T <: Enum] {
  val t: Class[T]

  def myMethod(name: String): T = {
    MyJavaClass.staticMethod(name, t)
  }
}

but I don't like having to add a t field to all classes that want to use this trait.

like image 694
three-cups Avatar asked Feb 13 '14 20:02

three-cups


People also ask

Can a trait take parameters Scala?

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

What is ClassTag in Scala?

A ClassTag[T] stores the erased class of a given type T , accessible via the runtimeClass field. This is particularly useful for instantiating Array s whose element types are unknown at compile time. ClassTag s are a weaker special case of scala. reflect.

Can Scala trait have variables?

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.

What is type erasure in Scala?

Type erasure refers to the runtime encoding of parameterized classes in Scala. It is simply performed by Scala compiler in which it removes all the generic type information after compilation. In Scala, generics are erased at runtime, which means that the runtime type of List[Int] and List[Boolean] is actually the same.


1 Answers

Nice and common way of working around type erasure in Scala is to use ClassTags. They're usually passed as implicit parameters. Unfortunately, traits can't take constructor parameters, so the best that we can have is:

import scala.reflect.ClassTag

trait MyTrait[T <: Enum] {
  val ttag: ClassTag[T]

  def myMethod(name: String): T = {
    MyJavaClass.staticMethod(name, ttag.runtimeClass.asInstanceOf[Class[T]])
  }
}

Then, every class extending MyTrait must be defined like this:

class MyClass[T <: Enum](/*your params, if any*/)(implicit val ttag: ClassTag[T]) extends MyTrait[T] {
  /*your class body*/
}

Then, if you have some concrete enum MyEnum, you can create instances of your class seamlessly:

new MyClass[MyEnum](/*your params, if any*/)
like image 113
ghik Avatar answered Oct 12 '22 16:10

ghik