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
Related
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'm trying to add an implicit value to (what I believe is) the companion object of a case class, but this implicit value is not found.
I'm trying to achieve something like the following:
package mypackage
object Main {
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = ...
serialize(out, caseClassInstance)
// the above line makes the compiler complain that there is no
// Serializer[MyCaseClass] in scope
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
...
}
}
object MyCaseClass {
// implicits aren't found here
implicit val serializer: Serializer[MyCaseClase] = ...
}
case class MyCaseClass(s: String) {
// some other methods
}
I've explicitly added the package here to show that both the MyCaseClass case class and object should be in scope. I know that the object is actually being constructed because I can get this to compile if I add
implicit val serializer = MyCaseClass.serializer
to main (though notably not if I add import MyCaseClass.serializer).
I'm concerned that the MyCaseClass object is not actually a companion of the case class, because if I explicitly define apply and unapply on the object and then attempt to call MyCaseClass.apply("string") in main, the compiler gives the following error:
ambiguous reference to overloaded definition,
both method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
and method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
match argument types (String)
val a = InputRecord.apply("string")
^
If it's not possible to take this approach, is there a way to use type classes with case classes without creating an implicit value every time it must be brought into scope?
EDIT: I'm using scala 2.10.3.
EDIT 2: Here's the example fleshed out:
package mypackage
import java.io.{DataOutput, DataOutputStream}
object Main {
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = new DataOutputStream(System.out)
serialize(out, caseClassInstance)
// the above line makes the compiler complain that there is no
// Serializer[MyCaseClass] in scope
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
implicitly[Serializer[T]].write(out, t)
}
}
object MyCaseClass {
// implicits aren't found here
implicit val serializer: Serializer[MyCaseClass] = new Serializer[MyCaseClass] {
override def write(out: DataOutput, t: MyCaseClass): Unit = {
out.writeUTF(t.s)
}
}
}
case class MyCaseClass(s: String) {
// some other methods
}
trait Serializer[T] {
def write(out: DataOutput, t: T): Unit
}
This actually compiles, though. I am getting this issue when using Scoobi's WireFormat[T] instead of Serializer, but can't provide a concise, runnable example due to complexity and the Scoobi dependency. I will try to create a more relevant example, but it seems as though the issue is not as general as I thought.
It turns out that the type class instances actually need to be implicit values, rather than objects. The MyCaseClass object above works because its serializer is assigned to an implicit value. However, this implementation
object MyCaseClass {
implicit object MyCaseClassSerializer extends Serializer[MyCaseClass] {
override def write(out: DataOutput, t: MyCaseClass): Unit = {
out.writeUTF(t.s)
}
}
}
fails with the error
Main.scala:9: error: could not find implicit value for evidence parameter of type mypackage.Serializer[mypackage.MyCaseClass]
serialize(out, caseClassInstance)
^
In my real code, I was using an auxiliary function to generate the Serializer[T] (see https://github.com/NICTA/scoobi/blob/24f48008b193f4e87b9ec04d5c8736ce0725d006/src/main/scala/com/nicta/scoobi/core/WireFormat.scala#L137). Despite the function having its own explicit return type, the type of the assigned value was not being inferred correctly by the compiler.
Below is the full example from the question with such a Serializer-generator.
package mypackage
import java.io.{DataOutput, DataOutputStream}
object Main {
import Serializer._
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = new DataOutputStream(System.out)
serialize(out, caseClassInstance)
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
implicitly[Serializer[T]].write(out, t)
}
}
object MyCaseClass {
import Serializer._
// does not compile without Serializer[MyCaseClass] type annotation
implicit val serializer: Serializer[MyCaseClass] =
mkCaseSerializer(MyCaseClass.apply _, MyCaseClass.unapply _)
}
case class MyCaseClass(s: String)
trait Serializer[T] {
def write(out: DataOutput, t: T): Unit
}
object Serializer {
// does not compile without Serializer[String] type annotation
implicit val stringSerializer: Serializer[String] = new Serializer[String] {
override def write(out: DataOutput, s: String): Unit = {
out.writeUTF(s)
}
}
class CaseClassSerializer[T, A : Serializer](
apply: A => T, unapply: T => Option[A]) extends Serializer[T] {
override def write(out: DataOutput, t: T): Unit = {
implicitly[Serializer[A]].write(out, unapply(t).get)
}
}
def mkCaseSerializer[T, A : Serializer]
(apply: A => T, unapply: T => Option[A]): Serializer[T] =
new CaseClassSerializer(apply, unapply)
}
This related, simple code below prints 1.
object A{
implicit def A2Int(a:A)=a.i1
}
case class A(i1:Int,i2:Int)
object Run extends App{
val a=A(1,2)
val i:Int=a
println(i)
}
Scala 2.10:
class A(val x:Int=0) {
}
object A {
def apply(x:Int): A = new A(x) // works
def apply(): A = new A() // fails to compile
}
val b = A(123) // :-)
val a = A() // >-(
Solution?
Even though your code should work (I suspect some implicit argument being at work here)
you can simplify it by doing
object A {
def apply(x: Int=0): A = New A(x)
}
while being shorter there's the drawback of being less DRY
I've found extremely weird behaviour (scala 2.9.1 ) using and defining implicit values, and wondering if anyone can explain it, or if it's a scala bug?
I've created a self contained example:
object AnnoyingObjectForNoPurpose {
trait Printer[T] {
def doPrint(v: T): Unit
}
def print[T : Printer](v: T) = implicitly[Printer[T]].doPrint(v)
trait DelayedRunner extends DelayedInit {
def delayedInit(x: => Unit){ x }
}
// this works, as it should
object Normal extends DelayedRunner {
implicit val imp = new Printer[Int] {
def doPrint(v: Int) = println(v + " should work")
}
print(343)
}
// this compiles, but it shouldn't
// and won't run, cause the implicit is still null
object FalsePositive extends DelayedRunner {
print(123)
implicit val imp = new Printer[Int] {
def doPrint(v: Int) = println(v + " should not compile")
}
}
def main(args: Array[String]) {
implicit val imp = new Printer[Int] {
def doPrint(v: Int) = println(v + " should work")
}
print(44)
// print(33.0) // correctly doesn't work
Normal // force it to run
FalsePositive // force this to run too
}
}
Suppose you changed your definition of delayInit to be a no-op, i.e.
def delayedInit(x: => Unit) { }
Then in your main method do something like
println("FP.imp: " + FalsePositive.imp)
As expected that will print FP.imp: null, but the real point of the exercise is to illustrate that the block that defines the body of FalsePositive is acting like a regular class body, not a function body. It's defining public members when it sees val, not local variables.
If you added a method to AnnoyingObjectForNoPurpose like the following, it wouldn't compile because print's implicit requirement isn't satisfied.
def fails {
print(321)
implicit val cantSeeIt = new Printer[Int] {
def doPrint(v: Int) = println(v + " doesn't compile")
}
}
However if you defined a class along the same principle, it would compile, but fail at runtime when initialized, just like your FalsePositive example.
class Fine {
print(321)
implicit val willBeNull = new Printer[Int] {
def doPrint(v: Int) = println(v + " compiles, but fails")
}
}
To be clear, the compile behavior of Fine has nothing to do with the presence of the implicit. Class/object initializers are very happy to compile with val initializers which reference undefined vals.
object Boring {
val b = a
val a = 1
println("a=%s b=%s".format(a, b))
}
Boring compiles just fine and when it is referenced, it prints a=1 b=0
It seems like your question boils down to "Should the body of a class/object deriving from DelayedInit be compiled as if it's a class body or a function block?"
It looks like Odersky picked the former, but you're hoping for the latter.
That's the same bug as if I write this:
object Foo {
println(x)
val x = 5
}
It ain't a bug. Your constructor flows down the object body and happens in order. DelayedInit isn't the cause. This is why you need to be careful when using val/vars and ensure they init first. This is also why people use lazy val's to resolve initialization order issues.
Is there a way to pass an implicit parameter into a curried function. I am using a dirty fix (se below) but it is not pretty. I would love to be able to pass the implicit var "i" as a implicit param.
case class myLoaner() {
implicit val i = "How to get this val into scope within the session function"
def withCode[T](session: => T): Either[Exception, T] = {
try {
Right(session)
} catch {
case ex: Exception => {
Left(ex)
}
}
}
}
object Test {
def main(args: Array[String]) {
val r = myLoaner()
r.withCode {
implicit val imp = r.i // I want to get rid of this line of code and use the implict val defined above directly
val h = new Helper
h.run
}
}
class Helper {
def run(implicit i: String) {
println(i)
}
}
}
After val r = myLoaner(), you can write
import r.i
or
import r._
to do what you want. Alternatively, you can mark r itself implicit and provide this extra definition:
implicit def loanerString(implicit loaner: myLoaner): String = loaner.i
... but now a little bit too many implicits start floating around for my taste, so use that wisely. Sometimes too much implicit magic harms the readability and understandability of your code.
You can always pass implicit parameters directly, e.g. as h.run(r.i).