I have a generic method which a generic type parameter T which is a subclass of MyClass. Inside that method, I want to create e new instance of T, how can I do that?
This doesn't work (because of type erasure):
object Demo extends App {
def myMethod[T <: MyClass](): Unit = {
val t = new T // gives error: class type required by T found
}
myMethod[MySubclassA]()
}
abstract class MyClass
class MySubclassA extends MyClass
class MySubclassB extends MyClass
It fails to work, but not (primarily) because of type erasure, but because your definition should make sense for all T which satisfy the type bounds, and new T doesn't. E.g. T can be MyClass or an abstract subclass, or a subclass without a parameter-less constructor, or a trait (traits can extend classes), or...
If a runtime error is good enough, you can go with Sergey Lagutin's solution. But more reasonable for most cases would be to pass some way to create a T to myMethod. Possibly as an implicit argument, e.g.
class Factory[T](f: () => T) {
def make(): T = f()
}
object Factory {
implicit val MySubclassAFactory =
new Factory(() => new MySubclassA)
implicit val MySubclassBFactory =
new Factory(() => new MySubclassB)
}
def myMethod[T <: MyClass](implicit factory: Factory[T]): Unit = {
val t = factory.make()
...
}
myMethod[MySubclassA] // works
myMethod[MyClass] // compilation error
myMethod[ASubclassForWhichFactoryIsNotDefined] // compilation error
You may use ClassTag to achieve your goal:
def myMethod[T <: MyClass : ClassTag]: T =
implicitly[ClassTag[T]].runtimeClass.newInstance().asInstanceOf[T]
println(myMethod[MySubclassA]) // MySubclassA#66d2e7d9
println(myMethod[MySubclassB]) // MySubclassB#1efbd816
Related
I use the factory pattern with generics. The idea is to create the right implementation (BlockType1Impl or BlockType2Impl) depending on the type of A which is a case class( BlockchainType1 or BlockchainType2). I don't put any Type Bounds constraints.
Code
After looking at this example on the apply method with generic types
trait BlockTypeFactory[A]{
def findTransactions( blocks: Seq[A], address: String): Seq[TransactionResponse]
}
object BlockTypeFactory{
// I want this method to return the correct implementations
def getBlockExplorer[A](blockType: A): BlockTypeFactory[A] = {
blockType match {
case type1: BlockchainType1 => new BlockTypeFactory[BlockchainType1](new BlockType1Impl)
// error : Expression of type BlockTypeFactory[BlockType1Impl] doesn't conform with the expected type BlockTypeFactory[A]
case type2: BlockchainType2 => new BlockType2Impl
}
}
def apply[A](implicit ev: BlockTypeFactory[A],blockType: A):BlockTypeFactory[A] = ev
}
But I get an error about expected type . What is exactly wrong ?
Other classes
class BlockType1Impl extends BlockTypeFactory[BlockchainType1]
class BlockType2Impl extends BlockTypeFactory[BlockchainType2]
case class BlockchainType1(...)
case class BlockchainType2(...)
Your code doesn't work because the compiler doesn't know where to get the implicit instances of BlockTypeFactory.
In order to achieve your goal you can use Type Classes.
This way is extensible, you can have more than one factory per class if you want (you need to play with implicits scope) and you can define standard factories for some types.
You can code implicit instances of your case classes inside BlockTypeFactory object, but this is the way it is usually done.
// your type class
trait BlockTypeFactory[A] {
def create:A
}
case class BlockchainType1()
object BlockchainType1 {
// type 1 impl
implicit val factory:BlockTypeFactory[BlockchainType1] = new BlockTypeFactory[BlockchainType1] {
def create: BlockchainType1 = BlockchainType1()
}
}
case class BlockchainType2()
object BlockchainType2 {
// type 2 impl
implicit val factory:BlockTypeFactory[BlockchainType2] = new BlockTypeFactory[BlockchainType2] {
def create: BlockchainType2 = BlockchainType2()
}
}
object BlockTypeFactory {
// get factory
def apply[A:BlockTypeFactory]:BlockTypeFactory[A] = implicitly[BlockTypeFactory[A]]
// or create
def create[A:BlockTypeFactory]:A = implicitly[BlockTypeFactory[A]].create
}
val instance1 = BlockTypeFactory[BlockchainType1].create
val instance2 = BlockTypeFactory.create[BlockchainType2]
This pattern is called Type Class, and it is used to get ad hoc polymorphism. In your example, you need a polymorphic method findTransactions for each class defined on BlockTypeFactory.
If I have 1 trait and 2 objects:
trait MyClass {
type T <: MyClass
def foo(): ClassTag[T] = {...}
}
object ChildClass1 extends MyClass {
type T = String
}
object ChildClass2 extends MyClass {
type T = Option[String]
}
is it possible to implement foo() in MyClass, such that ChildClass1.foo() yields ClassTag[String], and ChildClass2.foo() yields ClassTag[Option].
If not, what's the easiest way to bypass it? It should be noted that the implementation of T may be inner classes/objects, so hacking reflection may have some side effects.
Ok, it's possible that I don't completely understand your goal, but from what I can see, you are trying to create a trait with an upper bound type, and you also want to be able to get the type at runtime, correct?
So let's assume you have a Foo trait:
class MyClass // not important
trait Foo[T <: MyClass] {
def foo: ClassTag[T]
}
If you want an object implementation, the solution is trivial, since you know the type at compile time:
class MyClassSubclass extends MyClass // also not important
object FooObject extends Foo[MyClassSubclass] {
def foo: ClassTag[MyClassSubclass] = ClassTag(classOf[MyClassSubclass])
}
But if you want a class, then you can solve the problem with the implicitly + context bound combo in a pretty readable way:
class FooImpl[T <: MyClass : ClassTag] extends Foo[T] {
def foo: ClassTag[T] = implicitly[ClassTag[T]]
}
I would like to propose a dirty and impaired answer, please advice me if you have any better idea:
lazy val mf: ClassTag[T] = {
val clazz = this.getClass
val name = clazz.getName
val modifiedName = name + "T"
val reprClazz = Utils.classForName(modifiedName)
Manifest.classType(reprClazz)
}
it only works if the subclass is a singleton object.
Is there a way for the this keyword in a super class to refer to that class's subclass? Specifically, I am trying to do the following (the Json refers to Play's Json library):
abstract class A() {
def toJson[T](implicit writes: Writes[T]): JsValue = Json.toJson(this)
}
case class B(myProperty: String) extends A
object B { implicit val bFormat = Json.format[B] }
This gives the error No Json serializer found for type A. Try to implement an implicit Writes or Format for this type.. So it's saying it can't serialize an object of type A, which makes sense. The goal, however, is for the this in Json.toJson(this) to refer to the subclass (which, in this instance, is B).
Is there any way to accomplish this? If not, is there any other way I can implement the Json.toJson(...) method in the superclass without having to implement in the subclass (and all other subclasses of A)?
The common trick to refer to the current subclass from the parent, is to use F-bounded polymorphism:
// Here `T` refers to the type of the current subclass
abstract class A[T <: A[T]]() {
this: T =>
def toJson(implicit writes: Writes[T]): JsValue = Json.toJson(this)
}
// We have to specify the current subclass in `extends A[B]`
case class B(myProperty: String) extends A[B]
object B { implicit val bFormat = Json.format[B] }
println(B("foo").toJson)
This won't allow you to call toJson for any generic A though:
val a: A[_] = B("foo")
println(a.toJson) // Doesn't compile with:
// No Json serializer found for type _$1.
// Try to implement an implicit Writes or Format for this type.
To fix this you would have to save Writes for the subtype at the point of object creation:
abstract class A[T <: A[T]](implicit writes: Writes[T]) {
this: T =>
def toJson: JsValue = Json.toJson(this)
}
Or alternatively using the context bound notation:
abstract class A[T <: A[T] : Writes] {
this: T =>
def toJson: JsValue = Json.toJson(this)
}
And since this F-bounded polymorphism thing is just an implementation detail and always refering to a generic A as A[_] is quite boilerplate-y, you can move this code to an intermediate abstract class.
So a full example looks like this:
abstract class A() {
def toJson: JsValue
}
abstract class AImpl[T <: AImpl[T] : Writes] extends A {
this: T =>
def toJson: JsValue = Json.toJson(this)
}
case class B(myProperty: String) extends AImpl[B]
object B { implicit val bFormat: Format[B] = Json.format[B] }
val a: A = B("foo")
println(a.toJson)
In Scala, it's possible to specify whether a function or class is covarient or contravarient in the following manner
class Foo[+arg] // covarient
class Bar[-arg] // contravarient
What are the real world uses of this feature?
I know the compiler runs checks to make sure that the stated entity is actually covarient or otherwise, but what is the benefit of even adding such annotations?
The simplest case where your probably already using it without knowing it is the scala collections.
class A()
class B() extends A
case class Container[T](elem : T)
val listOfA:List[A] = List[B](new B(),new B())
val containerOfA:Container[A] = Container[B](new B()) // fails
Imagine you have the following hierarchy:
class A
class B extends A
Covariance. Covariant type can be used as return type:
class Foo[+arg] { // Covariant
def getArg(): arg = ???
}
def testCovariant(): Unit = {
val fooB = new Foo[B]
val foo: Foo[A] = fooB
// returns only objects of class derived from A
// so it is safe
val a: A = foo.getArg()
}
So you can use any of Foo[DerivedClass]where Foo[BaseClass] is used, because anywhere Foo[BaseClass].getArg is called BaseClass is expected as result and any DerivedClass can be returned and assigned to it.
Contravariance. Contravariant type can be used as method parameter type:
class Bar[-arg] { // Contravariant
def setArg(p: arg): Unit = ???
}
def testContravariant(): Unit = {
val barA = new Bar[A]
val bar: Bar[B] = barA
// can set B to bar which is actually Bar[A]
// but Bar[A].setArg(p: A) can accept any object
// of type derived from A
// so it is safe
bar.setArg(new B)
}
Again. You can use any of Bar[DerivedClass] where Bar[BaseClass] is used, because anywhere Bar[DerivedClass].setArg(p: DerivedClass) is called DerivedClass is expected as argument and any Bar[BaseClass] can be used in this context, because you can always pass DerivedClass to Bar[BaseClass].setArg(p: BaseClass).
so, here's a bit of a contrived example:
trait MyTrait {
type T <: MyTrait
val listOfT:List[T]
def getFirst:T
//def getOne:T = if( listOfT.length > 0 ) { getFirst } else { this }
}
class MyClass extends MyTrait {
type T = MyClass
override val listOfT:List[T] = List[MyClass](this)
override def getFirst:T = listOfT.head
}
The question sort of has two parts:
Is there some other way to do this where the return types in MyClass could just be "MyClass" instead of having to specify "type T = MyClass" ? Basically I want to be able to add this trait to a class without really having to have the subclass change its implementation significantly or think about the type system... to just return members of itself, and have the trait accept anything as long as it is covariant on the subtype. Does this even make sense?
in MyTrait, if uncommented, getOne method will give an error "type mismatch:"
found : MyTrait.this.type (with underlying type MyTrait)
required: MyTrait.this.T
If I were to change the return type to this.type, I'd get the opposite found/required type mismatch. Either return value actually has the same type (and is actually the same object).
What's the correct way to handle these kinds of situations?
Is this what you want?
trait MyTrait[T <: MyTrait[T]] { self: T =>
val listOfT: List[T]
def getFirst: T
def getOne: T = if (listOfT.length > 0) getFirst else self
}
class MyClass extends MyTrait[MyClass] {
override val listOfT: List[MyClass] = List[MyClass](this)
override def getFirst: MyClass = listOfT.head
}
It gets rid of type T = MyClass (allowing you to just put MyClass in a return type) and fixes the compile error in the definition of getOne.