I need to define a val in my companion object which is initialized with a method which takes the companion class as parameter.
I want to handle this with traits to not repeat myself. My Problem ist, that X.getClass ist not the same as classOf[X]. The first is the class of the companion object and the second is the class of the companion class, but I need to get the companion class without hardcoding it directly.
Basically I need something like this:
trait Foo {
}
object FooCompanionObject[f <: Foo] {
val fClazz = classOf[f]
}
// Bar's fClass should be classOf[Bar]
case class Bar extends Foo;
object Bar extends FooCompanionObject[Bar];
The problem is that I cannot get the class of an generic type due to type erasure
There are several problems in your code. First, as you already said, the type will be erased, second objects (object FooCompanionObject[f <: Foo]) don't take type parameters and third, objects can not be extended (object Bar extends FooCompanionObject). To do what you want, you have to create an abstract base class for your companion objects, that takes a type parameter, which may be constrained to a specific type if you like, and has to be context bound on ClassTag. From the ClassTag you can then get the runtime class by calling runtimeClass on it. The final solution could look like this:
import scala.reflect.ClassTag
import scala.reflect.classTag
trait Foo
abstract class Companion[A <: Foo : ClassTag] {
val fClazz = classTag[A].runtimeClass
}
class Bar extends Foo
object Bar extends Companion[Bar]
scala> Bar.fClazz
res2: Class[_] = class Bar
Related
I know a trait can extend a class which has an empty parameter constructor:
class Foo
trait Bar extends Foo
but is it possible to extend a class which constructor has some parameters?
class Foo(b: Boolean)
trait Bar extends Foo(true)
Is it possible to achieve this? It seems it's not possible. but why?
Thanks
Yes, it's possible, you just can't give constructor arguments:
trait Bar extends Foo { ... }
But to instantiate it you need to call the constructor as well:
new Foo(false) with Bar
Making the arg a val seems to work.
scala> class Foo(val b: Boolean)
defined class Foo
scala> trait Bar extends Foo {override val b = true}
defined trait Bar
This also works if you make the class a case class which automatically turns the args in to vals.
EDIT
As #Aleksey has pointed out, this compiles but it's a trait that can't be instantiated so, no, it still doesn't seem possible. You'll have to make Bar a class.
scala> class Bar extends Foo(false) {println(b)}
defined class Bar
scala> new Bar
false
In Scala I want to return a instance of a class for a method defined in a trait which uses generics, the code example I have is this:
File 1
package packOne
import packTwo.A
trait MyTrait[T <: MyTrait[T <: A]] {
def otherFunct(): String
def funct[T <: A](): T
}
File 2
package packTwo
import packOne.MyTrait
abstract class A(someParameter: String) {}
class B(someParameter: String) extends A(someParameter) {}
object B extends MyTrait[B] { // <--- the B inside MyTrait here is the class not the object, or at least that is what I want
def otherFunct(): String = "Hello"
def funct[B](): C = new B("hi") // <--- I think here is the key
}
basically what I want is an interface that have method to return a concrete implementation of class A, in an implementing object (which happen to be a companion object for a class extending A).
Why do I want that to be on an object?, is because I want to call that method without the need of an instance (like an static method in java), so that I can call B.funct() and have an instance of B class kind of like a factory method, for other classes extending A for example a call to X.funct will return an instance of class X.
I have tried to remove the generic type from the function definition except on the return type of the function and just leave it in the trait definition (like def funct(): T) but that does not work either.
I am quite new to Scala so if you could explain it for dummies and avoid complex scala unique concepts I would appreciate
How about simply:
trait A
class B(someParameter: String) extends A
trait MyTrait[T <: A] {
def otherFunct: String //Parentheses on parameterless methods with no side effects and no serious computation are generally unidiomatic in Scala
def funct: T //Note, no generic parameter on this method
}
object B extends MyTrait[B] {
def otherFunct = "Hello"
def funct = new B("hi")
}
And then:
B.funct //returns a new `B`
The apply method is often used in this factory style (e.g. Seq.apply() which is equivalent to Seq())
I have the following code:
trait Base[A,B] {
def name: String
}
trait BaseCompanion[A,B] {
def classOfBase: Class[_ <: Base[A,B]] // Can I implement something generic here ?
}
case class First(name: String) extends Base[Int,String]
object First extends BaseCompanion[Int,String] {
override def classOfBase: Class[_ <: Base[Int, String]] = classOf[First] // Can this part be generic ?
}
I don't want to override the classOfBase method in every concrete class that will extend BaseCompanion.This can be achieved by changing BaseCompanion to:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
}
object First extends BaseCompanion[Int,String,First]
But I don't really like this solution, is there a way to do this without changing the signature of BaseCompanion and implement something generic inside the it ?
By the way today Companion object of any case class "defines" apply(...) method. Given the example above there will be a method similar to this:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
/* No need to implement in the companion of a case class that extends Base */
def apply(name: String): Base[A,B]
}
The return type of this apply method is known to the Companion perhaps there is a way to use this information.
Yes, it can be done with this change:
def classOfBase = this.getClass.getMethods.find(_.getName == "apply").get.
getReturnType.asInstanceOf[Class[_ <: Base[A,B]]]
Note that this assumes there is precisely one apply method. In practice, you should check this assumption.
Assuming that if what you want would work, the following would be possible:
case class First(name: String) extends Base[Int, String]
object First extends BaseCompanion[Int, String]
assert(First.baseClass == classOf[First])
Now if that would work, what would stop you from doing the following?
class Second extends BaseCompanion[Int, String]
val second = new Second
println(second.baseClass)
or
// case class Third not defined
object Third extends BaseCompanion[Int, String]
println(Third.baseClass)
What would that result in? Second and Third are not a companion object with an associated class. Second is a class itself!
The problem is that you cannot force your BaseCompanion trait to only be inherited by something that is a companion object. BaseCompanion therefore cannot use the special relation that companion objects and associated classes have. If you want information about the associated class with a companion object, you have to give BaseCompanion that information manually in the definition of your companion object.
The Scala compiler won't allow you to do this. You can work around this with reflection if you want, but whatever solution remains that accomplishes this has to take into account that you are effectively creating unpredictable runtime behaviour. In my opinion, it's best to just help the compiler figure it out, and supply the proper information at compile time.
I have a class such as this:
class NormalClass[T <: NormalClass[T]] {
object One
object Two
}
and I wish to be able to create a new instance of the above class in a typed trait. The following def make in MetaClass creates an instance of T but it lacks the internal objects associated with NormalClass.
trait MetaClass[T <: NormalClass[T]] {
def make:T = this.getClass.getSuperclass.newInstance.asInstanceOf[T]
}
I have two questions, what is the reason for the missing objects and what is the best way, using reflection, to initiate a new class with internal objects from its type
EDIT: More Detail
The problem I am facing is if I then create an instance using make e.g. var f = make and I try to access and object method e.g. f.One.getSomething I get the error value One is not a member of type parameter T.
So I think your problem in particular is the reflection:
this.getClass.getSuperclass.newInstance.asInstanceOf[T]
Here, this is your instance of MetaClass, and there's no particular reason to believe that the superclass of this is the class you want to instantiate. For example:
class Foo extends NormalClass[Foo]
object Foo extends MetaClass[Foo]
In this case, the superclass of the object Foo is not a NormalClass at all, it's java.lang.Object. As a result, it won't have members like One or Two, and you'll get a ClassCastException if you try to cast it to T.
If you want the make method to instantiate an object of type T, then you need to get the runtime class of T, and then use that to create the new instance. You can accomplish this by implicitly acquiring a ClassTag:
class NormalClass[T <: NormalClass[T]] {
object One
object Two
}
trait MetaClass[T <: NormalClass[T]] {
def make(implicit classTag: scala.reflect.ClassTag[T]): T =
classTag.runtimeClass.newInstance.asInstanceOf[T]
}
// declare a class and an object for creating instances of that class
class Foo extends NormalClass[Foo]
object Foo extends MetaClass[Foo]
// create a new instance of Foo and access its fields
val foo = Foo.make
foo.One
foo.Two
I'm not sure what the issue is. This works for me:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class NormalClass[T <: NormalClass[T]] {
object One
object Two
}
trait MetaClass[T <: NormalClass[T]] {
def make:T = this.getClass.getSuperclass.newInstance.asInstanceOf[T]
}
class X extends NormalClass[X]
// Exiting paste mode, now interpreting.
defined class NormalClass
defined trait MetaClass
defined class X
scala> new X with MetaClass[X]
res0: X with MetaClass[X] = $anon$1#404fe94c
scala> res0.One
res1: res0.One.type = NormalClass$One$#53d9f80
scala> res0.Two
res2: res0.Two.type = NormalClass$Two$#4d0948bd
If that doesn't answer your question, please clarify the issue you're having.
I'm trying to import a bunch of methods from one class to another without extending it. I've made it work but why one approach works and the other doesn't is beyond me.
Stripped down, here is what I'm trying to do
class A {def x() {println("x")}}
object A
class B {
import A._
def y() {x()}
}
And the compiler tells me "not found: value x"
But it works if I do either this
class C extends A
class B {
import C._
or if I do this
object C extends A
class B {
import C._
Can someone explain why this is the case?
The reason why your code example class C extends A is not working is that you import class members which can only exist in the class they are defined.
Whereas when you write object C extends A you will create a singleton (in Scala called object like the keyword) which represents an instance and allows you to import its members.
So, to make members of other classes visible you always have to extend them, either by an object or by another class/trait. It is not enough to declare a companion object of a class because it does not hold an instance of its companion class.
There also the possibility of using implicits.
You need to have a way to get from a instance of B to the desired instance of
A. In the example below I use a member value, but it should be possible to make
it a function as well.
The trait exposed exposes the this in B to the implicits declared in A.
The trait PathTo can be used to expose a path to the desired instance of A.
class A {
def a1(){ println("a1") };
def a2(){ println("a2") };
def a3(){ println("a3") };
}
object A{
def a1()(implicit a:A){a.a1};
def a2()(implicit a:A){a.a2};
def a3()(implicit a:A){a.a3};
//makes it possible to use a1() instead of a1()(this.a)
implicit def insertPathToA(implicit path:PathTo[A]):A=path.pathTo;
// Makes it possible to write this.a2() instead of this.a.a2();
implicit def convertPathToA(path:PathTo[A]):A=path.pathTo;
};
trait exposed[U]{
implicit def self:U=this.asInstanceOf[U];
}
trait PathTo[U]{
implicit def pathTo:U;
}
class B(val a:A) extends exposed[B] with PathTo[A] {
// imports the magic
import A._
override def pathTo:A=a;
def y() {
a1() ;
this.a2();
};
}