How can one let a superclass have access to its concrete instance's type?
class Base {
val t = typeOf[this.type]
}
class X extends Base {
}
assert((new X).t =:= typeOf[X]) <-- fails!!!
So, the idea is that Base.t should reflect the concrete type of the instance...
It's unfortunately a common misunderstanding of this.type: it isn't the class of the instance, it's the singleton type (i.e. the type which only has one member: this). It won't work without inheritance either.
This can be done using F-bounded polymorphism:
class Base[A <: Base[A] : TypeTag] {
val t = typeOf[A]
}
class X extends Base[X]
How about making t a method and making that generic.
import scala.reflect.runtime.universe._
class Base {
def myActualType[T <: Base](b: T)(implicit tt: TypeTag[T]) = typeOf[T]
}
class Foo extends Base
class Bar extends Foo
val bar = new Bar
assert(bar.myActualType(bar) =:= typeOf[Bar])
The downside is that you always have to send the object reference to it when you call it, but you get what you want.
Related
I need to provide type class instances for a bunch of case classes all derived from a single trait, but as far as I understand Scala compiler expects an instance for a specific class and doesn't go up the inheritance hierarchy. So this code:
trait Base
sealed trait Child extends Base
case class Concrete() extends Child
trait Printable[A] {
def print(value: A): String
}
object WtfTrait {
def print[A](x: A)(implicit ev: Printable[A]) = {
println(ev.print(x))
}
implicit val printableBase = new Printable[Base] {
override def print(value: Base): String = value.toString
}
val x = Concrete()
print(x)
}
doesn't compile with an error reading could not find implicit value for parameter ev: Printable[Impl]. Is there a way to define a single type class instance for the base trait and avoid repitition maybe by using Shapeless or something.
Guess you mean Printable[Concrete] (that's to say a Show typeclass instance).
Need to update to printableBase definition as bellow:
trait Base
sealed trait Child extends Base
case class Concrete() extends Child
trait Printable[A] {
def print(value: A): String
}
object WtfTrait {
def print[A](x: A)(implicit ev: Printable[A]) = {
println(ev.print(x))
}
// HERE
implicit def printableBase[T <: Base] = new Printable[T] {
override def print(value: T): String = value.toString
}
val x = Concrete()
print(x)
}
Printable can be made contravariant by adding a - sign:
trait Printable[-A]
This makes Printable[X] a subtype of Printable[Y] if Y is a subtype of X. In particular, Printable[Base] is a subtype of Printable[Concrete] and can be used when the compiler looks for an implicit of that type.
I am trying to get hold of a shapeless Generic for a case class with a marker trait, like this:
case class X(a:String)
trait UniversalTrait extends Any {}
object MyApp extends App {
val ok = Generic[X]
val notOk = Generic[X with UniversalTrait]
}
It doesn't compile, with error could not find implicit value for parameter gen: shapeless.Generic[X with UniversalTrait] in the notOk line. Why is that? And can something be done?
Side note: I thought that it might be something to do with from not being able to add the marker trait to the returned instance, so I attempted fixing things by adding this:
object UniversalTrait {
implicit def genGeneric[P1<:Product with UniversalTrait,P2<:Product,L<:HList]
(implicit constraint: P1 =:= P2 with UniversalTrait,
underlying: Generic.Aux[P2,L]): Generic.Aux[P1,L] = new Generic[P1]{
type Repr=L
def to(t: P1): Repr = underlying.to(t)
def from(r: Repr): P1 = underlying.from(r).asInstanceOf[P1]
}
}
However, the error remains.
Deriving works for algebraic data types only.
That is a (sealed) trait and case classes (objects) extending the trait.
case class X(a:String) extends UniversalTrait
sealed trait UniversalTrait extends Any {}
val ok = Generic[X]
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)
I have the following code snippet:
abstract class Foo[T <: Foo[T]] { self: T =>
def bar(x: T): T
def newFoo: Foo[T] = {
new Foo[T] { self: T =>
// ...
}
}
}
I have a need to generate a new instance of Foo within a method of my abstract class. Can anyone advise me on how best to approach this?
Thanks,
Hadil
The self-type self: T => implies that your Foo[T] must also be a T. new Foo[T] { ... } isn't an instance of T for any arbitrary T that makes up Foo[T]. You also can't add a self-type to an anonymous class like new Foo[T] { ... }, because it doesn't make sense. Either the concrete class is or isn't a T at that point.
Constructing a method like def newFoo: Foo[T] in a type-safe way isn't really possible with the self-type in place, because you'd need to know how to construct an arbitrary T. You might be able to do what you want with reflection, when each T has the same constructor.
import scala.reflect._
abstract class Foo[T <: Foo[T] : ClassTag] { self: T =>
def bar(x: T): T
def newFoo: Foo[T] = classTag[T].runtimeClass.newInstance.asInstanceOf[T]
}
class Bar extends Foo[Bar] {
def bar(x: Bar): Bar = x
}
scala> val b = new Bar
b: Bar = Bar#2a2d45ba
scala> b.newFoo
res1: Foo[Bar] = Bar#146ba0ac
This ceases to work when there are constructor parameters:
case class Baz(i: Int) extends Foo[Baz] {
def bar(x: Baz): Baz = x
}
scala> val baz = new Baz(0)
baz: Baz = Baz(0)
scala> baz.newFoo
java.lang.InstantiationException: Baz
at java.lang.Class.newInstance(Class.java:427)
at Foo.newFoo(<console>:16)
Well, you do not know the concrete class where Foo will be inherited in the future. So especially, you do not know which constructor parameters this class will have and how to supply arguments for them. If you really would want to do this, you would have to make some assumptions (that you cannot enforce at compile time) to achieve this.
So what you probably should do, is, leave this method abstract and implement it in a subclass. If this is not an option, you probably have some issues with your overall class design. Better present here what you want to model and ask for help.
If you assume, that the constructor of the concrete class won't have any parameters, you can implement newFoo just as
def newFoo = this.getClass.newInstance
There is no need for classTags or other fancy stuff.