I'm trying to use Scala reflection to define traits case classes and their companions could implement to become "exportable" (e.g. to Map[String,Any]) and "importable" from the same. It's working nicely for top level case classes, but I can't make it work for inner classes. I would know how to instantiate an inner class reflectively if I already had a handle on the enclosing instance, which i could reflect to an InstanceMirror, but for now I am writing a trait that will be implemented later, by top-level or inner classes.
I should be able to make this work, as long as the companion and the constructed instances will share the same enclosing instance. But I've not been able to figure out how to determine the companion's enclosing instance reflectively.
Here's a way simplified example of what I am trying to do, and the problem that occurs:
import scala.reflect.runtime.universe._;
trait CompanionOfReflectiveConstructable[T] {
def tType : Type;
lazy val mirror : Mirror = runtimeMirror( this.getClass.getClassLoader );
lazy val ctorDecl : Symbol = tType.declaration(nme.CONSTRUCTOR);
lazy val ctor : MethodSymbol = ctorDecl.asMethod;
lazy val tClass : ClassSymbol = tType.typeSymbol.asClass;
lazy val tClassMirror : ClassMirror = mirror.reflectClass( tClass );
lazy val ctorF : MethodMirror = tClassMirror.reflectConstructor( ctor );
// in real-life, i'd derive arguments from ctor.paramss
// but to highlight our issue, we'll assume a no arg constructor
def createInstance : T = ctorF().asInstanceOf[T];
}
trait ReflectiveConstructable;
object Test1 extends CompanionOfReflectiveConstructable[Test1] {
def tType = typeOf[Test1];
}
class Test1 extends ReflectiveConstructable;
class Outer {
object Test2 extends CompanionOfReflectiveConstructable[Test2] {
def tType = typeOf[Test2];
}
class Test2 extends ReflectiveConstructable;
}
Here's what happens.
scala> Test1.createInstance
res0: Test1 = Test1#2b52833d
scala> (new Outer).Test2.createInstance
scala.ScalaReflectionException: class Test2 is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror
at scala.reflect.runtime.JavaMirrors$JavaMirror.ErrorInnerClass(JavaMirrors.scala:126)
...
Test1 works great. The problem with Test2 is clear -- I need to to get my ClassMirror via an InstanceMirror rather than via my top level mirror. (See here, here, and here.) But, from within CompanionOfReflectiveConstructable, I don't know how to check whether I am inner or who my enclosing instance is, to conditionally perform the appropriate work. Does anyone know how to do this?
Many thanks!
The main problem that I see here is that you're using reflection inside of the companion object of an inner class. The class Test2 will have a field defined called $outer that contains the outer class, however, from the Test2 companion object, you cannot get the instance of Outer that you need to create Test2. The only work around that I can see, is to pass an optional instance to you're companion trait:
trait CompanionOfReflectiveConstructable[T] {
def tType: Type
def outer: Option[AnyRef] = None
val mirror = runtimeMirror(this.getClass.getClassLoader)
val tClassMirror = outer
.map(a => mirror.reflect(a).reflectClass(tType.typeSymbol.asClass))
.getOrElse(mirror.reflectClass(tType.typeSymbol.asClass))
val ctorF = tClassMirror.reflectConstructor(tType.declaration(nme.CONSTRUCTOR).asMethod)
// in real-life, i'd derive arguments from ctor.paramss
// but to highlight our issue, we'll assume a no arg constructor
def createInstance: T = ctorF().asInstanceOf[T]
}
trait ReflectiveConstructable
class Test1 extends ReflectiveConstructable
object Test1 extends CompanionOfReflectiveConstructable[Test1] {
def tType = typeOf[Test1]
}
class Outer {
object Test2 extends CompanionOfReflectiveConstructable[Test2] {
def tType = typeOf[Test2]
override def outer = Option(Outer.this)
}
class Test2 extends ReflectiveConstructable
}
It would be nice if there was a way to get the Outer instance from the Test2 companion object, but sadly it's not available at runtime.
Related
Why is structural equality comparison affected, after deserialisation to case class instance, by the location of case class definition being inside or outside another class. For example, the assertion in the following snippet
package example
import org.json4s.DefaultFormats
import org.json4s.native.JsonMethods.parse
class Foo {
case class Person(name: String)
def bar = {
implicit val formats = DefaultFormats
val expected = Person(name = "picard")
val actual = parse("""{"name": "picard"}""").extract[Person]
assert(expected == actual, s"$expected == $actual")
}
}
object Main extends App {
(new Foo).bar
}
fails with
`java.lang.AssertionError: assertion failed: Person(picard) == Person(picard)`
whilst it passes if we move Person definition outside class Foo like so
case class Person(name: String)
class Foo {
def bar = {
...
assert(expected == actual, s"$expected == $actual")
}
}
Note, in both cases, deserialisation seems to be successful, for example,
assert(expected.name == actual.name)
is satisfied irrespective of case class Person definition location.
Perhaps it is somehow affected by the implicit Manifest passed in to extract?
This is a bug.
https://github.com/json4s/json4s/issues/564
"Deserialized inner case classes cannot be compared with case classes initialized in code"
Looks like inner classes can't be meaningfully checked for equality since every instance holds a reference to the outer object. And these references are a part of equality check:
class Outer {
case class Inner(s: String)
}
val outer = new Outer()
val a = outer.Inner("x")
val b = outer.Inner("x")
println(a==b) //true
val c = new Outer().Inner("x")
println(a==c) //false
I need to access a companion class with a specified trait -- from a trait intended for case classes. I am almost certain that the Scala reflection library can accomplish this but I haven't quite been able to piece it together.
I created test code below that requires one section of ??? be filled in with some reflection magic. The code compiles and runs as is -- with a notification due to the missing functionality.
Some related answers that I have seen on StackOverflow were from 2.10. Scala 2.12 compatible please.
import scala.reflect.{ClassTag, classTag}
//for companion object
//accesses Fields of the associated case class to ensure the correctness
//note: abstract class -- not a trait due to issues using ClassTag on a trait
abstract class SupportsField1Companion[T: ClassTag] {
//gets the names of all Fields on the associated case class
val fieldNamesOfInstancedClass: Array[String] =
classTag[T].runtimeClass.getDeclaredFields.map(_.getName)
//prints the name and fields of the associated case class -- plus extra on success
def printFieldNames(extra: String = ""): Unit = {
val name = classTag[T].runtimeClass.getCanonicalName
val fields = fieldNamesOfInstancedClass.reduceLeft(_ + ", " + _)
println(s"Fields of $name: $fields" + extra)
}
}
//for case classes
//IMPORTANT -- please do not parameterize this if possible
trait SupportsField1 {
//some data for printing
val field1: String = this.getClass.getCanonicalName + ": field1"
//should get a reference to the associated companion object as instance of SupportsFieldsCompanion
def getSupportsFieldsCompanion: SupportsField1Companion[this.type] = //this.type may be wrong
??? //TODO reflection magic required -- need functionality to retrieve companion object cast as type
//calls a function on the associated Companion class
def callPrintFuncOnCompanion(): Unit =
getSupportsFieldsCompanion.printFieldNames(s" -- from ${this.getClass.getCanonicalName}")
}
//two case classes with the SupportsFieldsCompanion trait to ensure data is accessed correctly
object ExampleA extends SupportsField1Companion[ExampleA] {}
case class ExampleA() extends SupportsField1 {
val fieldA: String = "ExampleA: fieldA"
}
object ExampleB extends SupportsField1Companion[ExampleB] {}
case class ExampleB() extends SupportsField1 {
val fieldB: String = "ExampleB: fieldB"
}
object Run extends App {
//create instanced classes and print some test data
val exampleA = ExampleA()
println(exampleA.field1) //prints "ExampleA: field1" due to trait SupportsFields
println(exampleA.fieldA) //prints "ExampleA: fieldA" due to being of class ExampleA
val exampleB = ExampleB()
println(exampleB.field1) //prints "ExampleB: field1" due to trait SupportsFields
println(exampleB.fieldB) //prints "ExampleB: fieldB" due to being of class ExampleB
//via the SupportsFieldsCompanion trait on the companion objects,
//call a function on each companion object to show that each companion is associated with the correct case class
ExampleA.printFieldNames() //prints "Fields of ExampleA: fieldA, field1"
ExampleB.printFieldNames() //prints "Fields of ExampleB: fieldB, field1"
//test access of printFieldNames on companion object from instanced class
try {
exampleA.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleA: fieldA, field1 -- from ExampleA"
exampleB.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleB: fieldB, field1 -- from ExampleB"
} catch {
case _: NotImplementedError => println("!!! Calling function on companion(s) failed.")
}
}
There are lots of ways you can do this, but the following is probably one of the simplest that doesn't involve making assumptions about how Scala's companion object class name mangling works:
def getSupportsFieldsCompanion: SupportsField1Companion[this.type] =
scala.reflect.runtime.ReflectionUtils.staticSingletonInstance(
this.getClass.getClassLoader,
this.getClass.getCanonicalName
).asInstanceOf[SupportsField1Companion[this.type]]
This works as desired, but I'd probably type it as SupportsField1Companion[_], and ideally I'd probably avoid having public methods on SupportsField1 that refer to SupportsField1Companion—actually ideally I'd probably avoid this approach altogether, but if you're committed I think the ReflectionUtil solution above is probably reasonable.
Is there a way to get the parent class from an instance of an inner class using macros rather than run-time reflection?
I have a set of classes like this:
trait IdProvider {
type IdObject = Id.type
case class Id(underlying: Int)
}
case class SomeEntity(id: SomeEntity.Id)
object SomeEntity extends IdProvider
And some code that works with arbitrary IdProvider#Ids:
val lookup = Map[IdProvider#IdObject, Set[Operation]]
def can(operation: Operation, id: IdProvider#Id): Boolean = {
val idObject = findIdTypeFromInstance(id) // This is what I don't have
lookup.get(idObject).exists(s => s(operation))
}
Taking a leaf out of this gist by Paul P. I now have this macro:
def findIdTypeFromInstance[T <: AnyRef : c.WeakTypeTag](
c: blackbox.Context)(thing: c.Expr[T]): c.Expr[T] = {
import c.universe._
val companion = thing.actualType.typeSymbol.companion match {
case NoSymbol =>
c.abort(c.enclosingPosition, s"Instance of ${thing.actualType} has no companion object")
case sym => sym
}
def make[U: c.WeakTypeTag] = c.Expr[U](internal.gen.mkAttributedRef(companion))
make(c.WeakTypeTag(companion.typeSignature))
}
This works for simpler cases (top level case classes, classes and objects, and even nested case classes). However, when dealing with the IdProvider setup above the macro tries to generate this tree:
Select(This(TypeName("IdProvider")), TermName("Id"))
This results in an extremely long stack trace in my test, which starts with:
scala.reflect.internal.Types$TypeError: value is not a member of my.spec.MacroSpec
I have not been able to find a path from the instance or the companion (IdProvider#Id) to the parent class (in this case SomeEntity). Is there a way to get to SomeEntity or do I have to use run-time reflection?
The Id companion is basically a lazy val. You need the enclosing instance to retrieve its value because it's not a statically defined stable path.
With -Yshow-syms you can see it get added in mixin phase:
object SomeEntity
constructor SomeEntity
* method Id$lzycompute (private)
method apply (case <synthetic>)
value id
method readResolve (private <synthetic>)
method unapply (case <synthetic>)
value x$0 (<synthetic>)
* object Id (<synthetic> <stable>)
value <local SomeEntity>
* variable Id$module (private <local> <synthetic>)
The $outer field of an Id is added in explicitouter.
Is it easier just to expose the companion reference explicitly?
case class Id(underlying: Int) {
def c = Id
}
This is just a quick look; maybe there's a clever way to do it.
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.
What is the difference between defining an object using the new operator vs defining a standalone object by extending the class?
More specifically, given the type class GenericType { ... }, what is the difference between val a = new GenericType and object a extends GenericType?
As a practical matter, object declarations are initialized with the same mechanism as new in the bytecode. However, there are quite a few differences:
object as singletons -- each belongs to a class of which only one instance exists;
object is lazily initialized -- they'll only be created/initialized when first referred to;
an object and a class (or trait) of the same name are companions;
methods defined on object generate static forwarders on the companion class;
members of the object can access private members of the companion class;
when searching for implicits, companion objects of relevant* classes or traits are looked into.
These are just some of the differences that I can think of right of the bat. There are probably others.
* What are the "relevant" classes or traits is a longer story -- look up questions on Stack Overflow that explain it if you are interested. Look at the wiki for the scala tag if you have trouble finding them.
object definition (whether it extends something or not) means singleton object creation.
scala> class GenericType
defined class GenericType
scala> val a = new GenericType
a: GenericType = GenericType#2d581156
scala> val a = new GenericType
a: GenericType = GenericType#71e7c512
scala> object genericObject extends GenericType
defined module genericObject
scala> val a = genericObject
a: genericObject.type = genericObject$#5549fe36
scala> val a = genericObject
a: genericObject.type = genericObject$#5549fe36
While object declarations have a different semantic than a new expression, a local object declaration is for all intents and purpose the same thing as a lazy val of the same name. Consider:
class Foo( name: String ) {
println(name+".new")
def doSomething( arg: Int ) {
println(name+".doSomething("+arg+")")
}
}
def bar( x: => Foo ) {
x.doSomething(1)
x.doSomething(2)
}
def test1() {
lazy val a = new Foo("a")
bar( a )
}
def test2() {
object b extends Foo("b")
bar( b )
}
test1 defines a as a lazy val initialized with a new instance of Foo, while test2 defines b as an object extending Foo.
In essence, both lazily create a new instance of Foo and give it a name (a/b).
You can try it in the REPL and verify that they both behave the same:
scala> test1()
a.new
a.doSomething(1)
a.doSomething(2)
scala> test2()
b.new
b.doSomething(1)
b.doSomething(2)
So despite the semantic differences between object and a lazy val (in particular the special treatment of object's by the language, as outlined by Daniel C. Sobral),
a lazy val can always be substituted with a corresponding object (not that it's a very good practice), and the same goes for a lazy val/object that is a member of a class/trait.
The main practical difference I can think of will be that the object has a more specific static type: b is of type b.type (which extends Foo) while a has exactly the type Foo.