Consider the following program. There are a bunch of type definitions, and a trait, and an object extending this trait.
This is a very simplified version of my program. The type definitions and trait are inside the program, and the user is supposed fill out the details inside the object:
/* ---------------------------------------------------*/
/** the internal program */
case class Type1()
case class Type2()
case class Type3()
trait aTrait {
// some stuff here
}
/* ---------------------------------------------------*/
/** user side */
object samepleObject extends aTrait {
val object1 = new Type1()
val object2 = new Type1()
val object3 = new Type2()
val object4 = new Type3()
// list of all objects here
// this definition should be populated automatically.
val all = List(object1, object2, object3, object4)
}
The user is supposed to define a set of variables (of possibly different types). There is a variable all which is a List of all variables user has defined. The question is it possible to define and populate this variable automatically (possibly inside the aTrait trait)?
This reminds me a bit of what Enums. I think you can only achieve something like that with a mutable state in your object or aTrait. That also means handlinf thread safety.
You could do something like
/* ---------------------------------------------------*/
/** the internal program */
case class Type1()
case class Type2()
case class Type3()
import scala.collection.mutable
trait aTrait {
private[this] var registry = mutable.ListBuffer.empty[Value[_]]
case class Value[T](value: T) {
registry.synchronized { registry :+= this }
}
def all: List[Value[_]] = registry.toList
}
/* ---------------------------------------------------*/
/** user side */
object sampleObject extends aTrait {
val object1 = Value(new Type1())
val object2 = Value(new Type1())
val object3 = Value(new Type2())
val object4 = Value(new Type3())
}
val test = sampleObject.all
> test: List[sampleObject.Value[_]] = List(Value(Type1()), Value(Type1()), Value(Type2()), Value(Type3()))
However, I do not guarantee concurrency-issuelessness
Related
Is it possible to have a trait be a singleton?
What I am trying to achieve is to have a clean and lightweight API I can extend throughout my application like the following:
trait SingletonTrait {
// element I wish to be unique throughout my application
val singletonElement = ///
...
}
// uses *singletonElement*
object MainApplication extends SingletonTrait {
...
}
// uses *singletonElement*
class SomeClass(...) extends SingletonTrait {
...
}
In the same idea implied by a getOrCreate() function that would retrieve an existing instance of an element if one already exists or creates it otherwise.
Maybe just create value in companion object and reference it in trait?
trait SingletonTrait {
final lazy val singletonElement = SingletonTrait.SingletonElement
}
object SingletonTrait {
lazy val SingletonElement = {
println("Creating singleton element!")
"singleton element"
}
}
// uses *singletonElement*
class SomeClass() extends SingletonTrait {
println(s"Using ${singletonElement} in class.")
}
new SomeClass()
new SomeClass()
new SomeClass()
It prints:
Creating singleton element!
Using singleton element in class.
Using singleton element in class.
Using singleton element in class.
Technically you could do this like so
object SingletonElement {
var count = 0
}
trait SingletonTrait {
final val singletonElement = SingletonElement
}
object MainApplication extends SingletonTrait {
singletonElement.count = singletonElement.count + 1
}
class SomeClass extends SingletonTrait {
singletonElement.count = singletonElement.count + 1
}
We can test that the same object is used like so
new SomeClass
MainApplication
SingletonElement.count
which should output
res2: Int = 2
which shows the same SingletonElement was used.
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.
In below code I receive this error :
class Animal needs to be abstract, since: it has 5 unimplemented members. /** As seen from class Animal, the
missing signatures are as follows. * For convenience, these are usable as stub implementations. */ def
favFood_=(x$1: Double): Unit = ??? def flyingType_=(x$1: scala.designpatterns.Strategy.Flys): Unit = ??? def
name_=(x$1: String): Unit = ??? def sound_=(x$1: String): Unit = ??? def speed_=(x$1: Double): Unit = ???
If I initialize all of the instance variables of class Animal to _ then the code compiles correctly. What does these error mean ?
package scala.designpatterns
/**
*
* Decoupling
* Encapsulating the concept or behaviour that varies, in this case the ability to fly
*
* Composition
* Instead of inheriting an ability through inheritence the class is composed with objects with the right abilit built in
* Composition allows to change the capabilites of objects at runtime
*/
object Strategy {
def main(args: Array[String]) {
var sparky = new Dog
var tweety = new Bird
println("Dog : " + sparky.tryToFly)
println("Bird : " + tweety.tryToFly)
}
trait Flys {
def fly: String
}
class ItFlys extends Flys {
def fly: String = {
"Flying High"
}
}
class CantFly extends Flys {
def fly: String = {
"I can't fly"
}
}
class Animal {
var name: String
var sound: String
var speed: Double
var favFood: Double
var flyingType: Flys
def tryToFly: String = {
this.flyingType.fly
}
def setFlyingAbility(newFlyType: Flys) = {
flyingType = newFlyType
}
def setSound(newSound: String) = {
sound = newSound
}
def setSpeed(newSpeed: Double) = {
speed = newSpeed
}
}
class Dog extends Animal {
def digHole = {
println("Dug a hole!")
}
setSound("Bark")
//Sets the fly trait polymorphically
flyingType = new CantFly
}
class Bird extends Animal {
setSound("Tweet")
//Sets the fly trait polymorphically
flyingType = new ItFlys
}
}
You must initialize variables. If you don't, Scala assumes you're writing an abstract class and a subclass will fill in the initialization. (The compiler will tell you so if you have just a single uninitialized variable.)
Writing = _ makes Scala fill in the default values.
The point is to make you think about what happens when someone (e.g. you, after you forget that you need to set things first) calls something that uses e.g. the sound without it having been set.
(In general you should at least think carefully about whether this is the right way to structure your code; many fields that require initialization before usage is safe, without any mechanism to enforce initialization, is asking for problems.)
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.