I am trying to define a case class with some params that have a default value, but the default value requires an implicit parameter. I've tried something like this:
case class ChannelLatches(started: TestLatch, stopped: TestLatch)(implicit system: ActorSystem) {
def this()(implicit system: ActorSystem) = this(new TestLatch(), new TestLatch())(system)
}
and this:
case class ChannelLatches(started: TestLatch, stopped: TestLatch)(implicit system: ActorSystem) {
def this()(implicit system: ActorSystem) = this(new TestLatch(), new TestLatch())(system)
}
but in both cases, the compiler does not recognize my new constructor. Any pointers?
The issue is not in the case class or its constructor. When you get compilation error like
scala> val channelLatches = new ChannelLatches
<console>:11: error: could not find implicit value for parameter system: ActorSystem
val channelLatches = new ChannelLatches
^
it means that you don't have an implicit variable of type ActorSystem available as a single identifier in the scope.
Both your code examples (they are exactly the same code, right?) and #Eastsun's example are perfectly legal code:
scala> class ActorSystem
defined class ActorSystem
scala> class TestLatch
defined class TestLatch
scala> case class ChannelLatches(started: TestLatch = new TestLatch, stopped: TestLatch = new TestLatch)(implicit system: ActorSystem)
defined class ChannelLatches
scala> implicit val actor = new ActorSystem
actor: ActorSystem = ActorSystem#586f403e
scala> val channelLatches = new ChannelLatches
channelLatches: ChannelLatches = ChannelLatches(TestLatch#521a74af,TestLatch#46e2b745)
Note the implicit val actor which makes it possible for the compiler to supply the missing parameter implicitly.
See A Tour of Scala: Implicit Parameters for introduction about implicit parameters.
--- Edit 2012-03-05: Added alternative example where ChannelLatches is inner class of Something
If you want ChannelLatches to be an inner class of something, you really don't need to pass the ActorSystem instance to the inner class instances as inner classes can access values from outer objects. A Tour of Scala: Inner Classes
scala> class ActorSystem
defined class ActorSystem
scala> class TestLatch
defined class TestLatch
scala> class Something(implicit val as: ActorSystem) {
| case class ChannelLatches(started: TestLatch, stopped: TestLatch) {
| def this() = this(new TestLatch(), new TestLatch())
|
| def actorSystem = as
| }
| }
defined class Something
scala> implicit val as = new ActorSystem
as: ActorSystem = ActorSystem#5481be8a
scala> val s = new Something
s: Something = Something#7139acf
scala> val cl = new s.ChannelLatches
cl: s.ChannelLatches = ChannelLatches(TestLatch#38764254,TestLatch#5bfcb5c1)
scala> cl.actorSystem == as
res0: Boolean = true
Related
How to define a wrapper function/class addActorToSystem() for
trait Stage extends Actor
class Stage1(i:Int) extends Stage
class Stage2(i:Int) extends Stage
and
implicit val system = ActorSystem("mySystem")
instead of the call to
system.actorOf(Props(new Stage1(123)), "myStage1")
The following does not work
You cannot create an instance of [Stage2] explicitly using the constructor (new)
def addActorToSystem(act: Stage, i: Int)(name: String)(implicit sys: ActorSystem) = {
sys.actorOf(Props(act(i)), name)
}
Maybe something like this would help you:
def addActorToSystem[T <: Stage](act: Class[T], i: Int)(name: String)(implicit sys: ActorSystem) = {
sys.actorOf(Props(act, i), name)
}
And usage like follows:
val s1 = addActorToSystem(classOf[Stage1], 1)("s1")
val s2 = addActorToSystem(classOf[Stage2], 2)("s2")
Creating actor without ActorContext defined (by using constructor) is not allowed.
The only one reason why this works in Props is the fact that constructor invocation is handled as by-name parameter thus its evaluation is deffered
This is a follow-up to my previous question:
Suppose I create the following test converter.scala:
trait ConverterTo[T] {
def convert(s: String): Option[T]
}
object Converters {
implicit val toInt: ConverterTo[Int] =
new ConverterTo[Int] {
def convert(s: String) = scala.util.Try(s.toInt).toOption
}
}
class A {
import Converters._
def foo[T](s: String)(implicit ct: ConverterTo[T]) = ct.convert(s)
}
Now when I tried to call foo in REPL it fails to compile:
scala> :load converter.scala
Loading converter.scala...
defined trait ConverterTo
defined module Converters
defined class A
scala> val a = new A()
scala> a.foo[Int]("0")
<console>:12: error: could not find implicit value for parameter ct: ConverterTo[Int]
a.foo[Int]("0")
^
import Converters._ in class A does not cut it. You can remove it and the code will still compile. The moment the compiler needs to find in actual implicit is not in class A, where foo is just declared.
The compiler needs to find a ConverterTo[Int] in implicit scope at the moment you call a.foo[Int](..) that is in the REPL. So this is where the import needs to be.
Had object Converters and trait ConverterTo been named the same (so there would be a companion object) the import would not be needed.
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.
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!
I'm quite new to Scala, but I'm trying to implement the following situation. Suppose I have a trait:
trait SomeTrait {
def kakaw
}
And two Scala objects that extend it:
object SampleA extends SomeTrait {
def kakaw = "Woof"
}
object SampleB extends SomeTrait {
def kakaw = "Meow"
}
What I'd like to do is call one of these two object functions based on a parameterized function call. For example (and I know this is the furthest thing from correct):
class SomeOther {
def saySomething[T] = T.kakaw
}
So I can do something like:
val s = new SomeOther
s.saySomething[SampleA]
Is this at all possible in Scala?
& scala
Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_23).
Type in expressions to have them evaluated.
Type :help for more information.
scala> trait SomeTrait {
| def kakaw : String
| }
defined trait SomeTrait
scala> class SampleA extends SomeTrait {
| def kakaw = "Woof"
| }
defined class SampleA
scala> implicit val sampleA = new SampleA
sampleA: SampleA = SampleA#42c71191
scala> class SampleB extends SomeTrait {
| def kakaw = "Meow"
| }
defined class SampleB
scala> implicit val sampleB = new SampleB
sampleB: SampleB = SampleB#53601a4f
scala> class SomeOther {
| def saySomething[ T <: SomeTrait](implicit target : T) = target.kakaw
| }
defined class SomeOther
scala> val s = new SomeOther
s: SomeOther = SomeOther#5947e54e
scala> s.saySomething[SampleA]
res0: String = Woof
It’s a bit confusing because you’ll need to have an instance of your type to act on. Just passing a type may make the compiler happy but you certainly want to make sure that you supply the very instance of some type you want to work with.
(Considering singleton objects there may be a work around using implicit evidence parameters for that, but I wouldn’t do that unless really needed.)
So, in your case why don’t you just say
class SomeOther {
def saySomething(obj: SomeTrait) = obj.kakaw
}
val s = new SomeOther
s.saySomething(SampleA)