One aspect of Akka I've always just glossed over appears right in the canonical Hello World! example. That is, the syntax for creating a Props class:
val props = Props[MyActor]
Q. What mechanism in Scala is allowing for the type parameter (i.e. [MyActor]) to be specified in this way? I'm assuming this gets translated to a constructor/apply method on Props that takes a Class parameter? For instance, my guess is it's equivalent to:
val props = Props(classOf[MyActor])
I've always assumed classOf was "special" and somehow cheated in order to use the [] syntax. Since I see that Akka, a 3rd party library, utilizes the same syntax it would be great to see a simple REPL example that demonstrates how I can utilize this syntax for my own classes.
Instances of Props are ultimately of the following case class (https://github.com/akka/akka/blob/0511b07f3e50e0422379075ae76dd158e4d377fa/akka-actor/src/main/scala/akka/actor/Props.scala#L115):
final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any])
Since this is a case class, scala will generate default apply method of
Props.apply(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any])
The Props companion object has several other apply methods which create instances of this class for you, using the default apply method. In the case of Props[MyActor], this is the method:
def apply[T <: Actor: ClassTag](): Props = apply(defaultDeploy, implicitly[ClassTag[T]].runtimeClass, List.empty)
Props[MyActor] is syntactic sugar for Props.apply[MyActor](). So Props is using the reflection capabilities of ClassTag in order to get the runtime class of MyActor, so it can satisfy the parameter clazz: Class[_] of the Props case class.
It is the Scala ClassTag mechanism. For instance:
object Test {
def apply[T: ClassTag](s: String): Option[T] = ...
}
val foo = Test[Foo]("foo")
In the apply method you can simply do something like
val ctor = implicitly[ClassTag[T]].runtimeClass.getConstructors.head
in order to get access to the first constructor of T for example.
Related
I'm new to Scala and got into troubles with understanding this declaration:
Here's the declaration from Akka's Props object:
def apply[T <: Actor: ClassTag](): Props = __THE_DEFENITION_GOES_HERE__
Why can we use it like this:
val props = Props[TestActor]
where class TestActor extends Actor. I'm curious about how just by Generic Type argument, the compiler is able to find the appropriate method defenition. How does it work?
There is some special magic involved with the apply method in a Scala object. This:
val something = Hello()
is special shortcut syntax for this:
val something = Hello.apply()
Similarly, looking at your example:
val props = Props[TestActor]
is just short syntax for this:
val props = Props.apply[TestActor]()
The [TestActor] is just filling in the type argument for the apply method.
I'm new to both Scala and Akka and have been following this tutorial. I came across the following and wondering what exactly this syntax does/mean?
import akka.actor.Props
val props1 = Props[MyActor] //Not sure what this means???
val props2 = Props(new ActorWithArgs("arg")) // careful, see below
val props3 = Props(classOf[ActorWithArgs], "arg")
I'm not sure what the line commented with //Not sure what this means does? It seems like a generic trait that gives a parameterised type. If I look at the source code, akka.actor.Props is defined as an Object that extends the trait AbstractProps. However, AbstractProps is not defined with a type parameter i.e. AbstractProps[T]. Can someone explain how that above line works and what it does?
In Scala, any object which implements an apply method can be called without the new keyword, simply by calling MyObject(), which will automatically lookup for it's apply.
If you look at the companion object for Props, you'll see the following method defined:
/**
* Scala API: Returns a Props that has default values except for "creator"
* which will be a function that creates an instance
* of the supplied type using the default constructor.
*/
def apply[T <: Actor: ClassTag](): Props =
apply(defaultDeploy, implicitly[ClassTag[T]].runtimeClass, List.empty)
This apply takes one type parameter and no arguments. T <: Actor means that T, the type you're passing, must extend Actor. That's how Scala knows how to create the object.
Additionally, any method with arity-0 in Scala may drop it's parenthesis. That's how you're seeing Props[MyActor] actually compile, as it is equivalent of Props[MyActor](), which is equivalent to Props.apply[MyActor]().
akka.actor.Props is defined as an Object that extends the trait
AbstractProps
Its also defined as a case class:
final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any])
This is a common pattern in Scala, a class with a companion object. The companion object frequently houses factory methods, and thats what your actually calling in your example.
val props1 = Props[MyActor]
This simply calls apply() of the companion object. You can omit the parentheses in Scala if no arguments are neccessary and apply is a special method that can be invoked directly on the object/instance. Say you have a sequence and want the element at index 1:
val s = Seq("one", "two", "three")
// These two are equivalent
s(1) // -> "two"
s.apply(1) // -> "two"
Ultimately your code can be rewritten as
val props1 = Props.apply[MyActor]()
In scala, I want to be able to say
val user = Node.create[User](...) // return User object
So here's what I have so far:
def create[T : TypeTag](map: Map[String, Any]) {
val type = typeOf[T]
// create class from type here???
}
I've been digging around how to create classes from generic types and found out that using ClassManifest seems to be deprecated. Instead, type tags are here, so I'm able to do something like this typeOf[T] and actually get the type.. but then I'm lost. If I could get the class, then I could use something like class.newInstance and manually set the fields from there.
Question is: given a type, can I get a class instance of the given type?
The easiest way in fact is to use ClassTag:
def create[T : ClassTag](map: Map[String, Any]): T = {
val clazz: Class[_] = classTag[T].runtimeClass
clazz.newInstance(<constructor arguments here>).asInstanceOf[T]
}
ClassTag is a thin wrapper around Java Class, primarily used for arrays instantiation.
TypeTag facility is more powerful. First, you can use it to invoke Java reflection:
import scala.reflect.runtime.universe._
def create[T: TypeTag](map: Map[String, Any]): T = {
val mirror = runtimeMirror(getClass.getClassLoader) // current class classloader
val clazz: Class[_] = mirror.runtimeClass(typeOf[T].typeSymbol.asClass)
clazz.newInstance(<constructor arguments here>).asInstanceOf[T]
}
However, Scala reflection allows to instantiate classes without dropping back to Java reflection:
def create[T: TypeTag](map: Map[String, Any]): T = {
// obtain type symbol for the class, it is like Class but for Scala types
val typeSym = typeOf[T].typeSymbol.asClass
// obtain class mirror using runtime mirror for the given classloader
val mirror = runtimeMirror(getClass.getClassLoader) // current class classloader
val cm = mirror.reflectClass(typeSym)
// resolve class constructor using class mirror and
// a constructor declaration on the type symbol
val ctor = typeSym.decl(termNames.CONSTRUCTOR).asMethod
val ctorm = cm.reflectConstructor(cm)
// invoke the constructor
ctorm(<constructor arguments here>).asInstanceOf[T]
}
If you want to create a class with overloaded constructors, it may require more work though - you'll have to select correct constructor from declarations list, but the basic idea is the same. You can read more on Scala reflection here
There is a way to do it with reflection: either runtime reflection, or in a macro. Regarding runtime reflection way, you can have a look at my blog post where I tried to do something like what you are trying to do now. Using compile-time reflection with macros might be a better option, depending on your need.
I am playing with the Play! framework and I wanted to create a factory called Services which will create new actors. I have this so far
class UserRegistration extends Actor {
def receive = {
case "foo" => "bar"
}
}
object UserRegistration {
val path: String = "user/registration"
}
object Services {
val system = ActorSystem("Services")
def apply[A<:Actor]: ActorRef = system.actorOf(Props[A], A.path)
}
And I wanted to create and pass messages to actors like this:
Services[UserRegistration] ? "hello"
but I get errors of the type could not find implicit value for evidence parameter of type ClassManifest[A]. Can anyone please tell me what am I doing wrong here? And if this is a valid construction in general (a best practice). I am pretty new in Scala and still learning stuff.
Thanks!
senia's answer works too, but if you want to specify a common path for each type of actor, you need a second implicit parameter(the first being the ClassManifest so that you can specify a path for each type of actor. Keep in mind that actor names have to be unique though, so you have to add something to that path.
First you define a class that holds the Path:
case class Path(value:String)
Then you define an implicit value in the companion object of your actor class:
object SomeActor {
implicit val path = Path("SomeActor")
}
Finally you modify the apply method to take an implicit class manifest as well as an implicit path.
def apply[A<:Actor](implicit cm:ClassManifest[A], path:Path[A]): ActorRef =
system.actorOf(Props[A], path.value + someIndex)
Method apply of object Props implicitly takes parameter of type ClassManifest[T].
apply [T <: Actor] (implicit arg0: ClassManifest[T])
You have to add such parameter into your method:
def apply[A<:Actor : ClassManifest]: ActorRef = system.actorOf(Props[A])
I'm trying to create an instance of a trait using this method
val inst = new Object with MyTrait
This works well, but I'd like to move this creation in to a generator function, ie.
object Creator {
def create[T] : T = new Object with T
}
I'm obviously going to need the manifest to somehow fix the type erasure problems, but before I get to this, I run in to 2 questions :
Even with an implicit manifest, Scala still demands that T be a trait. How do I add a restriction to create[T] so that T is a trait?
If I chose to use the Class.newInstance method to create the instance dynamically rather than using "new", how would I specify the "with" in "new Object with T"? Is it possible to dynamically create new concrete mixin types at runtime?
I'm not sure what the motivation is for your question, but you could consider passing a factory for T as an implicit parameter. This is known as using type classes or ad-hoc polymorphism.
object Test extends Application {
trait Factory[T] {
def apply: T
}
object Factory {
/**
* Construct a factory for type `T` that creates a new instance by
* invoking the by-name parameter `t`
*/
def apply[T](t: => T): Factory[T] = new Factory[T] {
def apply = t
}
}
// define a few traits...
trait T1
trait T2
// ...and corresponding instances of the `Factory` type class.
implicit val T1Factory: Factory[T1] = Factory(new T1{})
implicit val T2Factory: Factory[T2] = Factory(new T2{})
// Use a context bound to restrict type parameter T
// by requiring an implicit parameter of type `Factory[T]`
def create[T: Factory]: T = implicitly[Factory[T]].apply
create[T1]
create[T2]
}
At the other end of the spectrum, you could invoke the compiler at runtime, as detailed in this answer to the question "Dynamic mixin in Scala - is it possible?".
You can't do this (even with a Manifest). The code new Object with T involves creating a new anonymous class representing the combination of Object with T. To pass this to your create function, you would have to generate this new class (with new bytecode) at runtime, and Scala has no facilities for generating a new class at runtime.
One strategy might be to try to transfer the special functionality of the factory method into the class's constructor instead, and then use the constructor directly.
Another possible strategy is to create conversion functions (implicit or otherwise) to the traits you're interested in using with this class.