I noticed some gap around reflection and generics and I wonder if anybody can help here.
Let say I have the following abstract class:
abstract class Animal[T : Eatable: ClassTag] {
def eat(food: T) : Unit
}
And here is one implementation of it:
class Dog[DogFood] {
def eat (food: DogFood) : Unit = ???
}
class DogFood extends Eatable
And here I had some method that given an animal, feeds it
def feed[T <: Eatable](animal: Animal[T]) : Unit = {
val isAvailable = Storage.isAvailable[T]
???
}
Now let say I want to instantiate the implementation class using reflection as it is part of my system configuration:
val config = ....
val animalCls = config.getString("animal.type")
val animalInstance = animalCls = Class.forName(animalCls).newInstance
// Issue is here - I can't call this method as it uses classTags!
feed(animalInstance)
A solution might be:
val animalCls = config.getString("animal.type").asIsntanceOf[Animal[_]]
But then the following call inside feed will fail as it doesn't bind the right type:
Storage.isAvailable[T]
Any ideas here?
Related
I have the following classes in Scala:
class A {
def doSomething() = ???
def doOtherThing() = ???
}
class B {
val a: A
// need to enhance the class with both two functions doSomething() and doOtherThing() that delegates to A
// def doSomething() = a.toDomething()
// def doOtherThing() = a.doOtherThing()
}
I need a way to enhance at compile time class B with the same function signatures as A that simply delegate to A when invoked on B.
Is there a nice way to do this in Scala?
Thank you.
In Dotty (and in future Scala 3), it's now available simply as
class B {
val a: A
export a
}
Or export a.{doSomething, doOtherThing}.
For Scala 2, there is unfortunately no built-in solution. As Tim says, you can make one, but you need to decide how much effort you are willing to spend and what exactly to support.
You can avoid repeating the function signatures by making an alias for each function:
val doSomething = a.doSomething _
val doOtherthing = a.doOtherThing _
However these are now function values rather than methods, which may or may not be relevant depending on usage.
It might be possible to use a trait or a macro-based solution, but that depends on the details of why delegation is being used.
Implicit conversion could be used for delegation like so
object Hello extends App {
class A {
def doSomething() = "A.doSomething"
def doOtherThing() = "A.doOtherThing"
}
class B {
val a: A = new A
}
implicit def delegateToA(b: B): A = b.a
val b = new B
b.doSomething() // A.doSomething
}
There is this macro delegate-macro which might just be what you are looking for. Its objective is to automatically implement the delegate/proxy pattern, so in your example your class B must extend class A.
It is cross compiled against 2.11, 2.12, and 2.13. For 2.11 and 2.12 you have to use the macro paradise compile plugin to make it work. For 2.13, you need to use flag -Ymacro-annotations instead.
Use it like this:
trait Connection {
def method1(a: String): String
def method2(a: String): String
// 96 other abstract methods
def method100(a: String): String
}
#Delegate
class MyConnection(delegatee: Connection) extends Connection {
def method10(a: String): String = "Only method I want to implement manually"
}
// The source code above would be equivalent, after the macro expansion, to the code below
class MyConnection(delegatee: Connection) extends Connection {
def method1(a: String): String = delegatee.method1(a)
def method2(a: String): String = delegatee.method2(a)
def method10(a: String): String = "Only method I need to implement manually"
// 96 other methods that are proxied to the dependency delegatee
def method100(a: String): String = delegatee.method100(a)
}
It should work in most scenarios, including when type parameters and multiple argument lists are involved.
Disclaimer: I am the creator of the macro.
Is there any possibility to implicitly forward some of class methods to encapsulated object?
case class Entity(id: Int, name: String,) {
private lazy val lastScan = new LastScan
def getLastScanDate = lastScan.getLastScanDate
def updateLastScanDate = lastScan.updateLastScanDate
}
I want to avoid creating def updateLastScanDate = lastScan.updateLastScanDate just to forward methods to wrapped object.
In the plain language this is not possible. There used to be a compiler plugin by Kevin Wright to achieve this automatic delegation.
He seems to be working on an Autorproxy "Rebooted" version now that is macro based, making it straight forward to include in your project. I'm pasting here an example from its test sources:
trait Bippy {
def bippy(i : Int): String
}
object SimpleBippy extends Bippy {
def bippy(i: Int) = i.toString
}
#delegating class RawParamWrapper(#proxy pivot: Bippy)
val wrapper = new RawParamWrapper(SimpleBippy)
assert(wrapper.bippy(42) == "42")
I found an interesting scala implementation of Builder pattern, but I can't understand what a few lines mean:
case class Built(a:Int, b:String){}
trait Status
trait Done extends Status
trait Need extends Status
class Builder[A<:Status,B<:Status] private(){
private var built = Built(0,"")
def setA(a0:Int)={
built = built.copy(a=a0)
this.asInstanceOf[Builder[Done,B]]
}
def setB(b0: String) = {
built = built.copy(b = b0)
this.asInstanceOf[Builder[A,Done]]
}
def result(implicit ev: Builder[A,B] <:< Builder[Done,Done]) = built
}
object Builder{
def apply() = new Builder[Need,Need]
}
1) What does private() mean in class Builder[A<:Status,B<:Status] private() class declaration?
2) What is the meaning of implicit ev: Builder[A,B] <:< Builder[Done,Done] in result function?
1)
The private means that the primary constructor for Builder can not be accessed from outside.
Since there are no other constructors, the only way to get an instance is through the companion object with the apply method.
Example:
val builder = Builder()
2)
You have methods in Builder to set both parameters for the Built case-class.
The method result gives you the constructed Built-instance. The evidence makes sure that you have set both parameters and will not allow you to create an instance if you didn't do it.
Example (I did not test this, so please correct me if I am wrong):
val builderA = Builder().setA(3)
val resultA = builderA.result //should not compile because this is Builder[Done, Need]
val builderAB = builderA.setB("hello") //now this is Builder[Done, Done]
val resultAB = builderAB.result //should compile and yield Built(3, "hello")
For your first question, the keyword private in this position means the constructor for the class is private.
I have the following where I set information and extractors for different schemes of data:
trait DataScheme {
type Type <: List[Any]
class ExtractorMethods(ticker: String, dataList: List[Type]) {
def getDatetime(datum: Type): Date = new Date(datum(columnIndex(Names.datetime)).toString)
def upperDatum(date: Date): Type = dataList.minBy(datum => getDatetime(datum) >= date)
def lowerDatum(date: Date): Type = dataList.maxBy(datum => getDatetime(datum) <= date)
}
}
trait IndexScheme extends DataScheme {
type Type = (Date, Double, Double, Double, Double, Long)
class ExtractorMethods(ticker: String, dataList: List[Type]) extends super.ExtractorMethods(ticker: String, dataList: List[Type]){
def testing12(int: Int):Int = 12
val test123 = 123
}
}
I want anything extending DataScheme to use its ExtractorMethods methods (e.g. lowerDatum) but also have its own methods (e.g. testing12).
There is a class definition for lists of data elements:
class Data[+T <: DataScheme](val ticker: String, val dataList: List[T#Type], val isSorted: Boolean)
(implicit m: Manifest[T], mm: Manifest[T#Type]) extends Symbols {
def this(ticker: String, dataList: List[T#Type])(implicit m: Manifest[T], mm: Manifest[T#Type]) = this(ticker, dataList, false)(m: Manifest[T], mm: Manifest[T#Type])
val dataScheme: T
val extractorMethods = new dataScheme.ExtractorMethods(ticker, dataList.asInstanceOf[List[dataScheme.Type]])
}
A Data class should make accessible the methods in ExtractorMethods of the scheme so they can be used in the main program through the instance of Data that has been defined. For example if sortedData is an instance of Data[IndexScheme], the following works:
val lowerDatum = sortedData.extractorMethods.lowerDatum(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2010-03-31 00:00:00"))
but this does not:
val testing = sortedData.extractorMethods.testing12(123)
because 'testing 123 is not a member of sortedData.dataScheme.extractorMethods'. So my question is how can the subclasses of ExtractorMethods in the subtraits of DataScheme like IndexScheme be made accessible? How is it possible using Manifests and TypeTags? Thanks.
So you want the generic class Data[DataScheme] or Data[IndexScheme] to have access to the methods of whichever type Data has been parameterised with. You've tried to do this several different ways, from the evidence in your code.
To answer your last question - manifests can't help in this particular case and TypeTags are only part of the answer. If you really want to do this, you do it with mirrors.
However, you will have to make some changes to your code. Scala only has instance methods; there are no such things as static methods in Scala. This means that you can only use reflection to invoke a method on an instance of a class, trait or object. Your traits are abstract and can't be instantiated.
I can't really tell you how to clean up your code, because what you have pasted up here is a bit of a mess and is full of different things you have tried. What I can show you is how to do it with a simpler set of classes:
import scala.reflect.runtime.universe._
class t1 {
class Methods {
def a = "a"
def b = "b"
}
def methods = new Methods
}
class t2 extends t1 {
class Methods extends super.Methods {
def one = 1
def two = 2
}
override def methods = new Methods
}
class c[+T <: t1](implicit tag: TypeTag[T]) {
def generateT = {
val mirror = runtimeMirror(getClass.getClassLoader)
val cMirror = mirror.reflectClass(typeOf[T].typeSymbol.asClass)
cMirror.reflectConstructor(typeOf[T].declaration(nme.CONSTRUCTOR).asMethod)
}
val t = generateT().asInstanceOf[T]
}
val v1 = new c[t1]
val v2 = new c[t2]
If you run that, you'll find that v1.t.methods gives you a class with only methods a and b, but v2.t.methods gives a class with methods one and two as well.
This really is not how to do this - reaching for reflection for this kind of job shows a very broken model. But I guess that's your business.
I stick by what I said below, though. You should be using implicit conversions (and possibly implicit parameters) with companion objects. Use Scala's type system the way it's designed - you are fighting it all the way.
ORIGINAL ANSWER
Well, I'm going to start by saying that I would never do things the way you are doing this; it seems horribly over-complicated. But you can do what you want to do, roughly the way you are doing it, by
Using mixins
Moving the extractorMethods creation code into the traits.
Here's a greatly simplified example:
trait t1 {
class Methods {
def a = "a"
def b = "b"
}
def methods = new Methods
}
trait t2 extends t1 {
class Methods extends super.Methods {
def one = 1
def two = 2
}
override def methods = new Methods
}
class c1 extends t1
val v1 = new c1
// v1.methods.a will return "a", but v1.methods.one does not exist
class c2 extends c1 with t2
val v2 = new c2
// v2.methods.a returns "a" and v2.methods.one returns 1
I could replicate your modus operandi more closely by defining c1 like this:
class c1 extends t1 {
val myMethods = methods
}
in which case v1.myMethods would only have methods a and b but v2.myMethods would have a, b, one and two.
You should be able to see how you can adapt this to your own class and trait structure. I know my example doesn't have any of your complex type logic in it, but you know better than I what you are trying to achieve there. I'm just trying to demonstrate a simple mechanism.
But dude, way to make your life difficult...
EDIT
There are so many things I could say about what is wrong with your approach here, both on the small and large scale. I'm going to restrict myself to saying two things:
You can't do what you are trying to do in the Data class because it is abstract. You cannot force Scala to magically replace an uninitialised, abstract method of a non-specific type with the specific type, just by littering everything with Type annotations. You can only solve this with a concrete class which provides the specific type.
You should be doing this with implicit conversions. Implicits would help you do it the wrong way you seem fixated on, but would also help you do it the right way. Oh, and use a companion object, either for the implicits or to hold a factory (or bot).
I'm trying to do something like this:
import scala.swing
class componentMapper {
val map = Map[Class[_], Componenet]()
def apply(c: Class[_], component: Component) = map += (c -> componenet)
}
class Render extends ComponentMapper {
def getRenderer(value: AnyRef) = map(value.getClass)
}
This doesn't seem to work. What type parameter should I be using for Class?
I'm not entirely sure what the core problem is, but it's not the type parameter for class. It appears to be some weird type inference issue with "->". The following compiles and works just fine.
import scala.swing._
class ComponentMapper {
var map = Map[Class[_], Component]()
def apply(c: Class[_], component: Component) = map += ((c, component))
}
class Render extends ComponentMapper {
def getRenderer(value: AnyRef) = map(value.getClass)
}
Note that I had to make many small corrections to your code to even find what problem you were talking about.
I've filed a ticket in case in hopes that it's something fixable: https://lampsvn.epfl.ch/trac/scala/ticket/1974.