I have created a simple application with singleton object which contains local traits:
object Singleton {
trait FirstTrait {
val func1 = (i: Int) => i * 2
}
trait SecondTrait {
val func2 = (s: String) => s
}
trait ThirdTrait {
val func3 = () => println("Func 3")
}
}
And now, in Main object, I would like to do something like this:
object Main extends App {
val singleton = Singleton.FirstTrait//cannot do this
}
But I cannot do this (compile error). Why? Why I have not an access into this local trait? If I change Singleton object into:
object Singleton {
trait FirstTrait {
val func1 = (i: Int) => i * 2
}
trait SecondTrait {
val func2 = (s: String) => s
}
trait ThirdTrait {
val func3 = () => println("Func 3")
}
object FirstObject extends FirstTrait {
println(func1)
}
}
Main works well and program compiles. But I call another singleton object from Singleton, not a trait. I understand that trait cannot be instanced, but I think it is not a solution for it, because I have also a simple ScalaTest test name, which looks like
"Singleton" should "test it" in Singleton.FirstTrait{...}
and here I have an access into FirstTrait. So why I cannot use it in normal code?
I cannot understand it well. Maybe I am an idiot, but if someone could explain it to me well, I would be greatful.
It's a trait so you'll need to "instantiate" it properly:
val singleton = new Singleton.FirstTrait {}
// singleton: Singleton.FirstTrait = $anon$1#5e97da56
Note that technically a trait cannot be instantiated. The above expression is an instantiation of the anonymous class that extends the trait.
Singleton.FirstTrait is a type, not a value. You can't write
val singleton = Singleton.FirstTrait
any more than you can write
val singleton = Int
val singleton = String
etc. Traits and classes can have companion objects (objects with the same name), but FirstTrait obviously doesn't have one.
You can use it as a type, e.g.
def foo(x: Singleton.FirstTrait) = {}
val x: Singleton.FirstTrait = new Singleton.FirstTrait {}
Related
I need to write a generic class that can only allow the types Long,Double in place of [V]
class DummyGenericClass[V](data:Seq[V])
Also, there will be an implementation difference based on the type. I want to do something like
val typ = if (V is Long) "x" else "y"
What is the recommended/best practice in scala to write such code?
You can achieve it using sealed trait, which limits possible implementations to those that are defined in the same file:
sealed trait DummyGenericClass[V] {
val data: Seq[V]
val typ: String
}
class LongClass(val data: Seq[Long]) extends DummyGenericClass[Long] {
val typ = "x"
}
class DoubleClass(val data: Seq[Double]) extends DummyGenericClass[Double] {
val typ = "y"
}
If you want to have a generic constructor for DummyGenericClass the type safe way to do it is to use typeclass combined with factory pattern:
object DummyGenericClass {
trait Factory[T] {
def create(seq: Seq[T]): DummyGenericClass[T]
}
object Implicits {
implicit val longProvider =
new Factory[Long] {
def create(seq: Seq[Long]) = new LongClass(seq)
}
implicit val doubleProvider =
new Factory[Double] {
def create(seq: Seq[Double]) = new DoubleClass(seq)
}
}
def apply[T: Factory](seq: Seq[T]) = implicitly[Factory[T]].create(seq)
}
Which you can use the following way:
import DummyGenericClass.Implicits._
val foo = DummyGenericClass(Seq.empty[Long])
val bar = DummyGenericClass(Seq.empty[Double])
// Won't compile:
val baz = DummyGenericClass(Seq.empty[String])
The other way, that doesn't require defining a typeclass to create DummyGenericClass instances, is to pass ClassTag bound to T in the factory method. However this solution is not recommended since it's not a type safe way, as it allows one to pass type argument that is not supported and will fail at runtime.
If you want to have a generic method that uses this constructor, you have to add DummyGenericClass.Factory context bound to that method too:
def add[T: DummyGenericClass.Factory]
(a: DummyGenericClass[T], b: DummyGenericClass[T]) =
DummyGenericClass(a.data ++ b.data)
import DummyGenericClass.Implicits._
add(DummyGenericClass(Seq(1.0)), DummyGenericClass(Seq(2.0)))
I am looking for a way to initialize a companion object with arguments. I tried this, it has the risk for re-instantiation.
private[mypackage] class A(in:Int) {
def method = {}
}
object A {
var singleton: Option[A] = None
def getInstance(): A = {
if(singleton.isDefined)
singleton.get
else {
throw InitializationException("Object not configured")
}
}
def getInstance(in:Int): A = {
singleton = Some(new A(in))
singleton.get
}
}
Is there a better way?
Pure Scala way
Scala allows you to create a singleton object of a type using object keyword. Scala ensures only one instance of A is available in the system.
private[myPackage] object A {
val configValue = Config.getInt("some_value")
def fn: Unit = ()
}
type of A object
scala> object A {}
defined object A
scala> :type A
A.type
more about singleton objects in scala Explanation of singleton objects in Scala
Guice Annotations
import com.google.inject.Singleton
#Singleton
class A (val value: Int) {
def fn: Unit = ()
}
Classic Java way
Use synchronized keyword to protect the getInstance from creating more than one object when called. of course constructor of the class has to be private
You can use a lazy val to delay creation of your singleton, and base it on a var that should be updated once during start-up sequence:
object A {
// will be instantiated once, on first call
lazy val singleton: A = create()
private var input: Option[Int] = None
// call this before first access to 'singleton':
def set(i: Int): Unit = { input = Some(i) }
private def create(): A = {
input.map(i => new A(i))
.getOrElse(throw new IllegalStateException("cannot access A before input is set"))
}
}
I've a small sample code but it fail and I can't explain the reason
class ClassA(val name : String){
def hello ={
println ("hi "+name)
this
}
def Ok = {
println ("ok ")
this
}
}
trait TraitA {
self : ClassA =>
def sayHelloAgain ={
println ("hi again"+name)
this
}
}
perfectly I can do
val x = new ClassA("Mike") with TraitA
x.hello.Ok
this works ok too
val x = new ClassA("Mike") with TraitA
x.sayHelloAgain
but this doesn't
val x = new ClassA("Mike") with TraitA
x.hello.Ok.sayHelloAgain
trying in other way this doesnt works neither
class X extends ClassA("Mike") with TraitA
val x = new x
x.Ok.sayHelloAgain //not works
x.sayHelloAgain //works!!
this latest example is more clear to me, when I return this from method Ok I'm returning an instance from the classA instead of class X...
is possible "fix" this code and avoiding this behaviour or the only way how can accomplish this cascade method call is using implicit conversion
The problem is that the type returned by your methods in ClassA is determined locally, independently of TraitA, and the only type that makes sense in that context is ClassA. Running $ scalac -print test.scala shows:
[[syntax trees at end of cleanup]] // test.scala
package <empty> {
class ClassA extends Object {
<paramaccessor> private[this] val name: String = _;
<stable> <accessor> <paramaccessor> def name(): String = ClassA.this.name;
def hello(): ClassA = {
scala.this.Predef.println("hi ".+(ClassA.this.name()));
this
};
def Ok(): ClassA = {
scala.this.Predef.println("ok ");
this
};
def <init>(name: String): ClassA = {
ClassA.this.name = name;
ClassA.super.<init>();
()
}
};
abstract trait TraitA extends Object { self: ClassA =>
def sayHelloAgain(): ClassA
};
abstract trait TraitA$class extends { self: ClassA =>
def sayHelloAgain($this: ClassA): ClassA = {
scala.this.Predef.println("hi again".+($this.name()));
$this
};
def /*TraitA$class*/$init$($this: ClassA): Unit = {
()
}
}
}
ClassA has no sayHellowAgain method, explaining the behavior you've seen. It's not a type-safe operation within Scala's type system. As you've said, using implicit conversions is one way of doing something like what you suggest. Another option is the have both the class and the trait extend an abstract trait that defines the interface you want. It's tough to say what would be best without knowing what you're really trying to accomplish. It's a bit weird to see methods that return this in Scala, because that implies that you're relying on side-effects.
I have the following trait:
trait Mappable {
def toMap = {
val mappableFields = this.getClass.getDeclaredFields.filter(...)
...
}
}
mappableFields lists this.declaredFields and then applies static filters to the list; as such it is invariant for each class that implements Mappable, and ideally I'd like to be able to put it in the subclasses' singleton objects or something along those lines. My current solution is
object Mappable {
import scala.collection.mutable.Map
private val fieldMap = Map[Class[_], Array[Field]]()
def getFieldMap(clazz: Class[_]) = {
fieldMap.get(clazz) match {
case Some(array) => array
case _ => {
val mapFields = clazz.getDeclaredFields.filter(...)
fieldMap.put(clazz, mapFields)
mapFields
}}}}
trait Mappable {
def toMap = {
val mappableFields = Mappable.getFieldMap(this.getClass)
...
}
}
but I'm wondering if there's a better solution e.g. one that doesn't require a call to Map#get. I can't turn the trait into a class.
You could do something like this:
trait Mappable {
def companion: MappableCompanion
def toMap = {
val mappableFields = companion.mappableFields
...
}
}
trait MappableCompanion {
def thisClass: Class[_]
val mappableFields = thisClass.getDeclaredFields.filter(...)
}
Subtypes of Mappable would then also define a companion object:
class Foo extends Mappable {
def companion = Foo
}
object Foo extends { val thisClass = classOf[Foo] } with MappableCompanion
If you don't like the early initializer you can make MappableCompanion a class.
Given a trait MyTrait:
trait MyTrait {
def doSomething = println("boo")
}
it can be mixed into a class with extends or with:
class MyClass extends MyTrait
It can also be mixed upon instantiating a new instance:
var o = new MyOtherClass with MyTrait
o.doSomething
But...can the trait (or any other if that makes a difference) be added to an existing instance?
I'm loading objects using JPA in Java and I'd like to add some functionality to them using traits. Is it possible at all?
I'd like to be able to mix in a trait as follows:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
o = o with MyTrait //adding trait here, rather than during construction
o.doSomething
I have a idea for this usage:
//if I had a class like this
final class Test {
def f = println("foo")
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](val obj:Test) extends MyTrait
}
you can use this trait as below:
import MyTrait._
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
for your example code:
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
I hope this can help you.
UPDATED
object AnyTrait {
implicit def innerObj[T](o: MixTest[T]):T = o.obj
def ::[T](o: T) = new MixTest(o)
final class MixTest[T] private[AnyTrait](val obj: T) extends MyTrait
}
but this pattern has some restrict, you can't use some implicit helper method that defined already.
val a = new Test
a.f
val b = a :: AnyTrait
b.f1
b.f
val c = "say hello to %s" :: AnyTrait
println(c.intern) // you can invoke String's method
println(c.format("MyTrait")) //WRONG. you can't invoke StringLike's method, though there defined a implicit method in Predef can transform String to StringLike, but implicit restrict one level transform, you can't transform MixTest to String then to StringLike.
c.f1
val d = 1 :: AnyTrait
println(d.toLong)
d.toHexString // WRONG, the same as above
d.f1
An existing runtime object in the JVM has a certain size on the heap. Adding a trait to it would mean altering its size on the heap, and changing its signature.
So the only way to go would be to do some kind of transformation at compile time.
Mixin composition in Scala occurs at compile time. What compiler could potentially do is create a wrapper B around an existing object A with the same type that simply forwards all calls to the existing object A, and then mix in a trait T to B. This, however, is not implemented. It is questionable when this would be possible, since the object A could be an instance of a final class, which cannot be extended.
In summary, mixin composition is not possible on existing object instances.
UPDATED:
Related to the smart solution proposed by Googol Shan, and generalizing it to work with any trait, this is as far as I got. The idea is to extract the common mixin functionality in the DynamicMixinCompanion trait. The client should then create a companion object extending DynamicMixinCompanion for each trait he wants to have the dynamic mixin functionality for. This companion object requires defining the anonymous trait object gets created (::).
trait DynamicMixinCompanion[TT] {
implicit def baseObject[OT](o: Mixin[OT]): OT = o.obj
def ::[OT](o: OT): Mixin[OT] with TT
class Mixin[OT] protected[DynamicMixinCompanion](val obj: OT)
}
trait OtherTrait {
def traitOperation = println("any trait")
}
object OtherTrait extends DynamicMixinCompanion[OtherTrait] {
def ::[T](o: T) = new Mixin(o) with OtherTrait
}
object Main {
def main(args: Array[String]) {
val a = "some string"
val m = a :: OtherTrait
m.traitOperation
println(m.length)
}
}
I usually used a implicit to mix in a new method to an existing object.
See, if I have some code as below:
final class Test {
def f = "Just a Test"
...some other method
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object HelperObject {
implicit def innerObj(o:MixTest) = o.obj
def mixWith(o:Test) = new MixTest(o)
final class MixTest private[HelperObject](obj:Test) extends MyTrait
}
and then you can use MyTrait method with an already existing object Test.
val a = new Test
import HelperObject._
val b = HelperObject.mixWith(a)
println(b.f)
b.doSomething
in your example, you can use like this:
import HelperObject._
val o = mixWith(DBHelper.loadMyEntityFromDB(primaryKey));
o.doSomething
I am thinking out a prefect syntax to define this HelperObject:
trait MyTrait {
..some method
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](obj:Test) extends MyTrait
}
//then you can use it
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
// for your example
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
What about an implicit class? It seems easier to me compared to the way in the other answers with a final inner class and a "mixin"-function.
trait MyTrait {
def traitFunction = println("trait function executed")
}
class MyClass {
/**
* This inner class must be in scope wherever an instance of MyClass
* should be used as an instance of MyTrait. Depending on where you place
* and use the implicit class you must import it into scope with
* "import mypackacke.MyImplictClassLocation" or
* "import mypackage.MyImplicitClassLocation._" or no import at all if
* the implicit class is already in scope.
*
* Depending on the visibility and location of use this implicit class an
* be placed inside the trait to mixin, inside the instances class,
* inside the instances class' companion object or somewhere where you
* use or call the class' instance with as the trait. Probably the
* implicit class can even reside inside a package object. It also can be
* declared private to reduce visibility. It all depends on the structure
* of your API.
*/
implicit class MyImplicitClass(instance: MyClass) extends MyTrait
/**
* Usage
*/
new MyClass().traitFunction
}
Why not use Scala's extend my library pattern?
https://alvinalexander.com/scala/scala-2.10-implicit-class-example
I'm not sure what the return value is of:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
but let us say, it is DBEntity for our example. You can take the class DBEntity and convert it to a class that extends your trait, MyTrait.
Something like:
trait MyTrait {
def doSomething = {
println("boo")
}
}
class MyClass() extends MyTrait
// Have an implicit conversion to MyClass
implicit def dbEntityToMyClass(in: DBEntity): MyClass =
new MyClass()
I believe you could also simplify this by just using an implicit class.
implicit class ConvertDBEntity(in: DBEntity) extends MyTrait
I particularly dislike the accepted answer here, b/c it overloads the :: operator to mix-in a trait.
In Scala, the :: operator is used for sequences, i.e.:
val x = 1 :: 2 :: 3 :: Nil
Using it as a means of inheritance feels, IMHO, a little awkward.