I have an actor that creates children actors of type Child1 in this example. Child1 constructor takes two String's which are extracted from variables that reside in SomeTrait that is mixed into SomeActor isntance.
trait SuperTrait {
lazy val str1: Option[String] = None
lazy val str2: Option[String] = None
}
trait SomeTrait extends SuperTrait {
override lazy val str1: Option[String] = Some("Str1")
override lazy val str2: Option[String] = Some("Str2")
}
class SomeActor extends Actor {
this: SuperTrait =>
var child: Option[ActorRef] = None
override def preStart(): Unit = {
child = for {
st1 <- str1
st2 <- str2
} yield context.actorOf(Child1.props(st1, st2)))
}
}
Creation on SomeActor instance:
context.actorOf(Props[SomeActor with SomeTrait])
With this I am getting strange error:
SomeActor cannot be cast to SomeTrait.
It seems that extracting variables from Option container of SomeTrait throws that exception.
What am I missing here?
And it doesn't only happen with for comprehensions. Also when I try to do str1.getOrElse("") or add a getter to SomeTrait : def getStr1 = str1.getOrElse("")
As #ggovan said above, when using Akka you can't control the construction of an Actor. The Akka library takes care of that (and that's why you have Props to encapsulate the parameters passed to the constructor). The reason for this is, if your actor crashes its supervisor needs to be able to create a new instance of it.
When you use Props[X], Scala is using a a ClassTag to find the runtime class of the Actor. However, the ClassTag doesn't seem to pick up the anonymous class created when you call Props[X with Y], it picks up only the base class (in your case, SomeActor). A way around that is to use the by-name alternative of Props, so you can do this when creating the SomeActor:
val actor = sys.actorOf(Props(new SomeActor with SomeTrait))
That works and it picks up the overridden lazy vals too. Be sure, however, to read the downsides to that at http://doc.akka.io/docs/akka/snapshot/scala/actors.html (section "Dangerous variants").
Another option would be to use the Cake Pattern:
trait SomeTrait {
lazy val str1: Option[String] = None
lazy val str2: Option[String] = None
}
trait ActorTrait extends Actor {
this: SomeTrait =>
override lazy val str1 = Some("Str1")
override lazy val str2 = Some("Str2")
var child: Option[ActorRef] = None
override def preStart(): Unit = {
child = for {
st1 <- str1
st2 <- str2
} yield context.actorOf(Child1.props(st1, st2)))
}
}
class SomeActor extends ActorTrait with SomeTrait
In that case you can use the recommended Props[SomeActor] method to create the Props object.
Related
Usually the "memeber" in trait is defined as def variable:Type, then other memebers which depend on variable uses lazy val to prevent variable being null when getting initialized.
However if it is a piece of logic, e.g. a function call depends on variable will still throw null exception. Like the code below:
trait A {
def variable:Seq[String]
if (variable.size > 3) // check
println("too many strings")
}
case class B(vs:String*) extends A {
override val variable: Seq[String] = vs
//override def hi(): Unit = ???
}
val b = B("x", "y", "z")
println(b)
This will throw error "A.variable() is null".
Strangely, if I wrote variable as given constructor parameter, the error is gone.
case class B(override val variable:String*) extends A {
//override def hi(): Unit = ???
}
How I can delay the "check" and why the second case doesn't throw exception?
That's a use case for early initializers
case class B(vs: String*) extends {
override val variable: Seq[String] = vs
} with A {
//override def hi(): Unit = ???
}
In Scala, what is an "early initializer"?
https://docs.scala-lang.org/scala3/reference/dropped-features/early-initializers.html
Why am I able to serialize this:
// Serialize: OK
case class ClassWithType2[T:TypeTag](x:T) {
val tpe:java.lang.reflect.Type = Util.toJavaClass[T]
}
... but not this
class TypeAware[T:TypeTag]() {
val tpe:java.lang.reflect.Type = Util.toJavaClass[T]
}
// Serialize: FAIL.
// No valid constructor for ClassWithType1
// in: java.io.ObjectStreamClass.checkDeserialize
case class ClassWithType1[T:TypeTag](x:T) extends TypeAware[T]
Both seem have the same constructor type prototype:
[T:TypeTag](x:T)
and both extend scala.Serializable and java.io.Serializable
val s1:Serializable = ClassWithType1(x=123)
val s2:Serializable = ClassWithType2(x=123)
val s3:java.io.Serializable = ClassWithType1(x=123)
val s4:java.io.Serializable = ClassWithType2(x=123)
Its there a way to implement TypeAware subclasses that:
avoid having to declare tpe in every subclass (as ClassWithType2 does)?
allows the object to be serialized
Here's the test harness
class TypesTest {
#Test
def serializeTypeTest(): Unit = {
val obj2:Object = ClassWithType2(x=123)
Util.copyBySerialization(obj2) // Success!
val obj1:Object = ClassWithType1(x=123)
Util.copyBySerialization(obj1) // Fail
}
}
object Util {
def toJavaClass[T:TypeTag]: Class[_] = {
val tpe = typeOf[T]
runtimeMirror(tpe.getClass.getClassLoader).runtimeClass(tpe.typeSymbol.asClass)
}
def copyBySerialization[T](obj: T): T = deserialize(serialize(obj))
def serialize[T](obj: T): Array[Byte] = {
val byteOut = new ByteArrayOutputStream()
val objOut = new ObjectOutputStream(byteOut)
objOut.writeObject(obj)
objOut.close()
byteOut.close()
byteOut.toByteArray
}
def deserialize[T](bytes: Array[Byte]): T = {
val byteIn = new ByteArrayInputStream(bytes)
val objIn = new ObjectInputStream(byteIn)
val obj = objIn.readObject().asInstanceOf[T]
byteIn.close()
objIn.close()
obj
}
}
Just quoting the Javadoc:
To allow subtypes of non-serializable classes to be serialized, the
subtype may assume responsibility for saving and restoring the state
of the supertype's public, protected, and (if accessible) package
fields. The subtype may assume this responsibility only if the class
it extends has an accessible no-arg constructor to initialize the
class's state. It is an error to declare a class Serializable if this
is not the case. The error will be detected at runtime.
The ctor for TypeAware includes the implicit parameter.
Edit: one idea is to make the type tag a member. Or similar. It doesn't save as much syntax.
abstract class TypeAware {
protected def tt: TypeTag[_]
def tpe:java.lang.reflect.Type = Util.toJavaClass(tt)
}
case class ClassWithType1[T](x:T)(implicit val tt: TypeTag[T]) extends TypeAware
Edit, more linx:
tech page
faq
your question
I was going through the effective scala slides and it mentions on slide 10 to never use val in a trait for abstract members and use def instead. The slide does not mention in detail why using abstract val in a trait is an anti-pattern. I would appreciate it if someone can explain best practice around using val vs def in a trait for abstract methods
A def can be implemented by either of a def, a val, a lazy val or an object. So it's the most abstract form of defining a member. Since traits are usually abstract interfaces, saying you want a val is saying how the implementation should do. If you ask for a val, an implementing class cannot use a def.
A val is needed only if you need a stable identifier, e.g. for a path-dependent type. That's something you usually don't need.
Compare:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) } // ok
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = { // ok
Thread.sleep(5000) // really heavy number crunching
42
}
}
If you had
trait Foo { val bar: Int }
you wouldn't be able to define F1 or F3.
Ok, and to confuse you and answer #om-nom-nom—using abstract vals can cause initialisation problems:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko // zero!!
This is an ugly problem which in my personal opinion should go away in future Scala versions by fixing it in the compiler, but yes, currently this is also a reason why one should not use abstract vals.
Edit (Jan 2016): You are allowed to override an abstract val declaration with a lazy val implementation, so that would also prevent the initialisation failure.
I prefer not use val in traits because the val declaration has unclear and non-intuitive order of initialization. You may add a trait to already working hierarchy and it would break all things that worked before, see my topic: why using plain val in non-final classes
You should keep all things about using this val declarations in mind which eventually road you to an error.
Update with more complicated example
But there are times when you could not avoid using val. As #0__ had mentioned sometimes you need a stable identifier and def is not one.
I would provide an example to show what he was talking about:
trait Holder {
type Inner
val init : Inner
}
class Access(val holder : Holder) {
val access : holder.Inner =
holder.init
}
trait Access2 {
def holder : Holder
def access : holder.Inner =
holder.init
}
This code produces the error:
StableIdentifier.scala:14: error: stable identifier required, but Access2.this.holder found.
def access : holder.Inner =
If you take a minute to think you would understand that compiler has a reason to complain. In the Access2.access case it could not derive return type by any means. def holder means that it could be implemented in broad way. It could return different holders for each call and that holders would incorporate different Inner types. But Java virtual machine expects the same type to be returned.
I agree with the other answers about avoiding abstract vals for the reason that it provides more options to implementations.
There are cases where you might need them:
For a path-dependent type (as mentioned by #0__).
Where implementations might be expensive and it is used in a concrete def.
(Are there others? If so please comment and I'll add them in).
The more important things to know is when it is safe to override something with a val and to have a lazy val that does not override something.
Rule 1: Never override a val or def with a non-lazy val unless it is a constructor parameter:
trait TraitWithVal {
// It makes no difference if this is concrete or abstract.
val a: String
val b: String = a
}
class OverrideValWithVal extends TraitWithVal {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideValWithLazyVal extends TraitWithVal {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideValWithConstructorVal(override val a: String = "a") extends TraitWithVal
//class OverrideValWithDef extends TraitWithVal {
// // Compilation error: method a needs to be a stable, immutable value.
// override def a: String = "a"
//}
println((new OverrideValWithVal).b) // null
println((new OverrideValWithLazyVal).b) // a
println((new OverrideValWithConstructorVal).b) // a
The same rule applies to a def:
trait TraitWithDef {
// It makes no difference if this is concrete or abstract.
def a: String
val b: String = a
}
class OverrideDefWithVal extends TraitWithDef {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideDefWithLazyVal extends TraitWithDef {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideDefWithConstructorVal(override val a: String = "a") extends TraitWithDef
class OverrideDefWithDef extends TraitWithDef {
// Ok: b will be "a".
override def a: String = "a"
}
println((new OverrideDefWithVal).b) // null
println((new OverrideDefWithLazyVal).b) // a
println((new OverrideDefWithConstructorVal).b) // a
println((new OverrideDefWithDef).b) // a
You might be wondering whether it would be ok to override a val with another val so long as it isn't used during initialisation. There is at least one edge cases which break this:
trait TraitWithValAndLazyVal {
val a: String = "A"
def b: String = a
}
class OverrideLazyValWithVal extends TraitWithValAndLazyVal {
// Bad: This on its own is ok but not if it is indirectly referenced during initialisation and overridden.
override val a = "a"
val c = b
}
class OverrideValWithVal extends OverrideLazyValWithVal {
override val a = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // a
println((new OverrideValWithVal).c) // null
Given that we already apply this rule to overriding defs then this makes using vals a little more acceptable in my opinion.
If you use a linter to enforce the override keyword and make sure your code never has any override val definitions then you are good.
You might be able to allow final override val but it's possible there are other edge cases that I haven't thought of.
Rule 2: Never use a lazy val that is not overriding another lazy val or def.
As far as I can tell there also is no good reason to have a lazy val that isn't overriding something. All the examples that I can come up with where it is needed, it is needed only because it violates Rule 1 and exposes the edge case I described earlier.
For example:
trait NormalLookingTrait {
def a: String
val b: String = a
}
trait TraitWithAbstractVal extends NormalLookingTrait {
val c: String
}
class OverrideValWithVal extends TraitWithAbstractVal {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // null
println((new OverrideValWithVal).c) // a
So we make b a lazy val:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal2).a) // a
println((new OverrideValWithVal2).b) // a
println((new OverrideValWithVal2).c) // a
Looks ok, except when we go one step further:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
val d = b
}
class OverrideValWithVal3 extends OverrideValWithVal2 {
override val c = "a"
}
println((new OverrideValWithVal3).a) // a
println((new OverrideValWithVal3).b) // null
println((new OverrideValWithVal3).c) // a
println((new OverrideValWithVal3).d) // null
I now get what people mean when they say to only use lazy when it is absolutely necessary and never for delayed initialisation.
It's probably safe to break this rule if the trait / class is final but even that smells fishy.
Always using def seems a bit awkward since something like this won't work:
trait Entity { def id:Int}
object Table {
def create(e:Entity) = {e.id = 1 }
}
You will get the following error:
error: value id_= is not a member of Entity
I find some confusing use of trait in some unittesting code, such as:
trait MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
And then instantiate the trait using new and meanwhile some expressions wrapped by curly braces followed the instantiation.
test("it is a test") {
new MyTrait {
// do something with t1 and t2
}
}
I am confused by this strange syntax.
My question is:
why use follow trait instantiation by curly braces?
what is the purpose of trait instantiation in this case and other cases might also be helpful?
You are not instantiating the traits: traits by themselves cannot be instantiated; only non-abstract classes can. What you are doing here is using Scala's shorthand for both defining an anonymous/nameless class that extends the trait and instantiating it in the same statement.
val anonClassMixingInTrait = new MyTrait {
def aFunctionInMyClass = "I'm a func in an anonymous class"
}
Is the equivalent of:
class MyClass extends MyTrait {
def aFunctionInMyClass = "I'm a func in a named class"
}
val namedClassMixingInTrait = new MyClass
The difference is you can only instaniate that anonymous class at the time of definition since it doesn't have a name and it can't have constructor arguments.
Steve Buzzard already explained, what anonymous classes are, but you also asked for the purpose. The purpose here is, that in tests you often have some default values, you want to use in every test. Sometimes you also have state, that may be changed by some of the tests. To always start with correct values (tests may also run in parallel) you can encapsulate them in these anonymous instances. The code inside this anonymous instance is the constructor, which will be evaluated at instantiation, thus executing your tests.
val t = new MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
is the same as
val t = new AnyRef with MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
is the same as
val t = new Object with MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
Example from "Hands on Scala" by Li HAOYI. Chapter 5.
trait StrParser[T]{ def parse(s: String): T }
object StrParser{
implicit object ParseInt extends StrParser[Int]{
def parse(s: String) = s.toInt
}
implicit object ParseBoolean extends StrParser[Boolean]{
def parse(s: String) = s.toBoolean
}
implicit object ParseDouble extends StrParser[Double]{
def parse(s: String) = s.toDouble
}
}
def parseFromString[T](s: String)(implicit parser: StrParser[T]) = {
parser.parse(s)
}
implicit def ParseSeq[T](implicit p: StrParser[T]) = new StrParser[Seq[T]]{
def parse(s: String) = s.split(',').toSeq.map(p.parse)
}
parseFromString[Seq[Int]]("1,2,3")
ParseSeq is Constructor for StrParser with Type Seq[T] and implicit parameter p:StrParser[T].
And one more StrParser Constructor for Type [T, V]
implicit def ParseTuple[T, V](implicit p1: StrParser[T], p2: StrParser[V]) =
new StrParser[(T, V)]{
def parse(s: String) = {
val Array(left, right) = s.split('=')
(p1.parse(left), p2.parse(right))
}
}
Now we can make
parseFromString[Seq[(Int, Boolean)]]("1=true,2=false,3=true,4=false")
Result is Seq[(Int, Boolean)] = ArraySeq((1,true), (2,false), (3,true), (4,false))
I'd like to reduce the boilerplate needed to bind these akka actors.
At current, my code looks like this:
bind(classOf[ActorRef]).
annotatedWith(Names.named("mines")).
toProvider(new TypeLiteral[ActorProvider[MyActor]]() {}).
asEagerSingleton()
I'd like it too look like:
bindActor[MyActor].withName("mines")
I've tried to subclass AbstractModule to squeeze this concept in to no avail.
Pertinent code:
class ActorProvider[T <: Actor] #Inject() ( val key:Key[T], val injector:Injector, val system: ActorSystem ) extends Provider[ActorRef] {
def get = {
system.actorOf(Props(injector.getInstance(key)))
}
}
Check out https://github.com/codingwell/scala-guice/. Here is a sample based on it. It allows for
bindActor[MyActor].withName("mines")
Keep in mind you are binding a non-generic ActorRef and not Actor itself. This will create a binding for #Named("foo") ActorRef. You should never work with Actor directly.
You cannot get Key in the provider. Provider doesn't take any contextual injections like you tried with the Key or e.g. Injection Point. What you can do is create a different instance of the provider for each actor binding and inject it with ActorSystem afterwards. Alternatively you could change the API to include the actor system instance aswell.
trait AkkaModule extends AbstractModule {
// should be:
// this: AbstractModule =>
// see http://lampsvn.epfl.ch/trac/scala/ticket/3564
import ScalaModule._
private def binderAccess = super.binder // shouldn't need super
def bindActor[T <: Actor](implicit m: Manifest[T]) = new ActorBindingBuilder {
//Hack, no easy way to exclude the bind method that gets added to classes inheriting ScalaModule
//So we experamentally figured out how many calls up is the source, so we use that
//Commit 52c2e92f8f6131e4a9ea473f58be3e32cd172ce6 has better class exclusion
val mybinder = binderAccess.withSource((new Throwable).getStackTrace()(3))
val self = (mybinder bind classOf[ActorRef]).asInstanceOf[AnnotatedBindingBuilder[ActorRef]]
}
}
object AkkaModule {
class ActorProvider(val name: String) extends Provider[ActorRef] {
#Inject var system: ActorSystem = _
def get = {
system.actorFor(system.name + "/user/" + name)
}
}
trait ActorBindingBuilder {
val mybinder: Binder
val self: AnnotatedBindingBuilder[ActorRef]
def withName(name: String) = {
val provider = new ActorProvider(name)
self.annotatedWith(Names.named(name)).toProvider(provider)
mybinder.requestInjection(provider)
}
}
}
Something like this that leverages scala's type Manifest might work
http://www.scala-lang.org/api/current/scala/reflect/Manifest.html
where Foo is analogous to ActorRef and Bla is analogous to MyActor:
scala> import com.google.inject
import com.google.inject
scala> val binder:inject.Binder = null
binder: com.google.inject.Binder = null
scala> class Foo {}
defined class Foo
scala> class Bla extends Foo {}
defined class Bla
scala> def bind[T <: Foo:Manifest] = binder.bind( classOf[Foo] ).toProvider( new
inject.TypeLiteral[inject.Provider[T]](){} ).asEagerSingleton
bind: [T <: Foo](implicit evidence$1: Manifest[T])Unit
Maybe combine that with implicit conversion to convert a Binder to a MyBinder:
http://daily-scala.blogspot.com/2009/08/implicit-methods.html
class MyBinder {
def bindActor[T <: ActorRef:Manifest]( nameToBind:String ):Unit = ...
}
object MyBinder {
implicit def binderToMyBinder( ...
}
Good luck!