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]()
Related
Does scala provide a default apply method for a class?
I have a class:
class Player(tea: String, sal: Int = 0) {
val team = tea
private val salary = sal
}
So no apply method here, and I haven't defined any companion object for it, so no apply method from there too.
But I am able to do:
val player = Player("AAAA", 1000)
With no 'new' operator used, I understand that this line of code must invoke some apply method. But there is none defined by me. So how does it work?
Yes, since Scala 3, as described in the docs:
Scala case classes generate apply methods, so that values of case classes can be created using simple function application, without needing to write new.
Scala 3 generalizes this scheme to all concrete classes. Example:
class StringBuilder(s: String):
def this() = this("")
StringBuilder("abc") // old: new StringBuilder("abc")
StringBuilder() // old: new StringBuilder()
This works since a companion object with two apply methods is generated together with the class. The object looks like this:
object StringBuilder:
inline def apply(s: String): StringBuilder = new StringBuilder(s)
inline def apply(): StringBuilder = new StringBuilder()
The synthetic object StringBuilder and its apply methods are called constructor proxies. Constructor proxies are generated even for Java classes and classes coming from Scala 2. The precise rules are as follows:
A constructor proxy companion object object C is created for a concrete class C, provided the class does not have already a companion, and there is also no other value or method named C defined or inherited in the scope where C is defined.
Constructor proxy apply methods are generated for a concrete class provided
the class has a companion object (which might have been generated in step 1), and
that companion object does not already define a member named apply.
Each generated apply method forwards to one constructor of the class. It has the same type and value parameters as the constructor.
I want to the equivalent of x.asInstanceOf[T] when I don't know T until runtime. (I'm using Dotty, so Scala reflection is not available.)
I tried this, but it didn't work:
object DynaCaster:
def cast( victim: Any, asA: Class[_] ) =
val classTag = ClassTag.apply(asA)
_cast(victim)(classTag)
private def _cast[T](v: Any)(implicit ct: ClassTag[T]): T = v.asInstanceOf[T]
Intended use:
val x: SomeThing = ... // where SomeThing is a case class extending trait AnyThing
val anyThingValue = DynaCaster.cast(x, Class.forName("com.mystuff.AnyThing"))
// anyThingValue is now of class AnyThing
// Note: My actual use case cannot know the end types beforehand. For example, this won't
// work for my use:
// val anyThingValue: AnyThing = ...
What's my mysterious use case? I'm dynamically calling a class constructor obtained via Java reflection. Its arguments are typed to a trait, while the actual arg values are typed to concrete classes of that trait. I need to dynamically cast the concrete class values to their trait types in order to invoke the constructor.
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.
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.
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.