I have this:
case class Aaa() extends NClass {
def method1() = println("method1")
}
object Aaa extends NCompanion {
def method2() = println("method2")
}
I would like to implement something like the following pseudo code:
abstract class Xxx[T] {
// All the trash code of reflection/implicit should be in this class only
instance = new T()
companion = T
instance.method1()
companion.method2()
}
To use like this:
class Yyy extends Xxx[Aaa] {}
How can I implement this? It is better if I could use the new Scala Reflection API. Thanks in advance!
For now I am using a solution avoiding get the companion type with generics:
abstract class Xxx[T <: NClass[T], O <: NCompanion[T]](implicit tag: TypeTag[T]) {
def getInstance(): T
def getCompanion(): O
val classOfT = typeTag[T].mirror.runtimeClass(typeOf[T])
val className = classOfT.getName
println(s"$className")
val t = getInstance()
val manager = getCompanion()
}
Usage:
class Yyy extends Xxx[Aaa, Aaa.type] {
override def getInstance: Aaa = {
return new Aaa()
}
override def getCompanion: Aaa.type = {
return Aaa
}
}
Related
abstract class SuperClass {
def method() = this
}
class SubClass1 extends SuperClass {
def method1() = this
}
class SubClass2 extends SuperClass {
def method2() = this
}
val obj1 = new SubClass1()
obj1.method1().method() // this is ok
val obj2 = new SubClass2()
obj2.method().method2() // this is not ok, as method returns a SuperClass,
// which has no method named method2
So how to make the method return the subclass type so I can chain the operation in any order.
So far what I can think is to follow something like
abstract class SuperClass[T <: SuperClass[T]]
but I don't know how to continue that.
Something like this should work:
abstract class SuperClass {
def method(): this.type = this
}
I find the following approach works as well:
abstract class SuperClass[T <: SuperClass[T]] {
def method(): T = this.asInstanceOf[T]
}
class SubClass extends SuperClass[SubClass] {
def method1() = this
}
val obj = new SubClass()
obj.method1().method()
obj.method().method1()
I want to achieve the following:
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[T <: Super] {
def test = T.typeSpecific
}
val testerA = new Tester[SubA]
val testerB = new Tester[SubB]
testerA.test // should return 1
testerB.test // should return 2
Is something like this possible in Scala? This fails because the value of T is not found in Tester.test.
typeSpecific is not a static member, it belongs to instances of SubA and SubB, which you don't have. You also can't statically access anything from a type parameter (it's a type, not an object).
This won't work as is, because you don't have instances of SubA and SubB, nor can you obtain them via new Tester[SubA]. But you can require that Tester mixes in a type of Super in order to make it one (and thus have typeSpecific). This would require you change Super, SubA, and SubB to traits, and would also make your instance anonymous classes.
trait Super {
def typeSpecific: Int
}
trait SubA extends Super {
def typeSpecific = 1
}
trait SubB extends Super {
def typeSpecific = 2
}
// The self-type `this: A =>` requires the mix-in.
class Tester[A <: Super] { this: A =>
def test = typeSpecific
}
val testerA = new Tester[SubA] with SubA
val testerB = new Tester[SubB] with SubB
scala> testerA.test
res2: Int = 1
scala> testerB.test
res3: Int = 2
You could also require A <: Super as a constructor parameter for Tester, which is probably the cleaner option.
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[A <: Super](s: A) {
def test = s.typeSpecific
}
val testerA = new Tester(new SubA)
val testerB = new Tester(new SubB)
scala> testerA.test
res5: Int = 1
scala> testerB.test
res6: Int = 2
Any way you cut it, you're going to need an instance of SubA or SubB.
You're going to have to use reflection combined with typeTags to get your desired result. I warn you, it's somewhat ugly:
import scala.reflect.runtime.universe._
abstract class SuperClass {
def typeSpecific: Int
}
class SubA extends SuperClass {
def typeSpecific = 1
}
class SubB extends SuperClass {
def typeSpecific = 2
}
class Tester[T <: SuperClass: TypeTag] {
def test = typeTag[T].mirror.runtimeClass(typeOf[T]).newInstance.asInstanceOf[T].typeSpecific
}
I also feel I should mention that typeSpecific is not static as it is part of a class, in scala static members are defined in objects/companion objects only. Using objects it would be cleaner to do something like this:
trait SuperTrait {
def typeSpecific: Int
}
object SubA extends SuperTrait {
def typeSpecific = 1
}
object SubB extends SuperTrait {
def typeSpecific = 2
}
class Tester(testObject : SuperTrait) {
def test = testObject.typeSpecific
}
new Tester(SubA).test
new Tester(SubB).test
I have a trait and a class that extends the trait. I can use the methods from the trait as follows:
trait A {
def a = ""
}
class B(s: String) extends A {
def b = a
}
However, when I use the trait's method in the constructor like this:
trait A {
def a = ""
}
class B(s: String) extends A {
def this() = this(a)
}
then the following error appears:
error: not found: value a
Is there some way to define default parameters for the construction of classes in the trait?
EDIT: To clarify the purpose: There is the akka-testkit:
class TestKit(_system: ActorSystem) extends { implicit val system = _system }
And each test looks like this:
class B(_system: ActorSystem) extends TestKit(_system) with A with ... {
def this() = this(actorSystem)
...
}
because I want to create common creation of the ActorSystem in A:
trait A {
val conf = ...
def actorSystem = ActorSystem("MySpec", conf)
...
}
It's a little bit tricky because of Scala initialization order. The simplest solution I found is to define a companion object for your class B with apply as factory method:
trait A {
def a = "aaaa"
}
class B(s: String) {
println(s)
}
object B extends A {
def apply() = new B(a)
def apply(s: String) = new B(s)
}
I have the following classes/traits setup:
class RestService extends EntityReader[UserEntity]
with EntityReaderExtension {
def serveSomething() = {...}
}
trait EntityReader[EntityType <: StoredEntity] extends RestHelper {
protected def read(id:UUID): Option[EntityType] = {
// Read by id
}
}
trait EntityReaderExtension {
def serveExtensionMethod(id:UUID) = {
// val entity = read(id) match {...}
// copy values to other entity and serve
}
}
Is there a way i can use the method from trait EntityReader in trait EntityReaderExtension without extending?
I think what you want is an explicitly typed self reference.
trait EntityReaderExtension { self: EntityReader[_] =>
def serveExtensionMethod(id:UUID) = {
val entity = self.read(id) match {...}
}
}
I have the following trait:
trait Mappable {
def toMap = {
val mappableFields = this.getClass.getDeclaredFields.filter(...)
...
}
}
mappableFields lists this.declaredFields and then applies static filters to the list; as such it is invariant for each class that implements Mappable, and ideally I'd like to be able to put it in the subclasses' singleton objects or something along those lines. My current solution is
object Mappable {
import scala.collection.mutable.Map
private val fieldMap = Map[Class[_], Array[Field]]()
def getFieldMap(clazz: Class[_]) = {
fieldMap.get(clazz) match {
case Some(array) => array
case _ => {
val mapFields = clazz.getDeclaredFields.filter(...)
fieldMap.put(clazz, mapFields)
mapFields
}}}}
trait Mappable {
def toMap = {
val mappableFields = Mappable.getFieldMap(this.getClass)
...
}
}
but I'm wondering if there's a better solution e.g. one that doesn't require a call to Map#get. I can't turn the trait into a class.
You could do something like this:
trait Mappable {
def companion: MappableCompanion
def toMap = {
val mappableFields = companion.mappableFields
...
}
}
trait MappableCompanion {
def thisClass: Class[_]
val mappableFields = thisClass.getDeclaredFields.filter(...)
}
Subtypes of Mappable would then also define a companion object:
class Foo extends Mappable {
def companion = Foo
}
object Foo extends { val thisClass = classOf[Foo] } with MappableCompanion
If you don't like the early initializer you can make MappableCompanion a class.