If I have defined a variable b val b:B. Is it possible to print the value of b each time b is assigned to a new value. Like the code below:
case class B(name:String) {
}
var b = B("123")
b = B("xxx")
println(s"b is changed to $b")
b = B("xxJJx")
println(s"b is changed to $b")
I hope the code println(s"b is changed to $b") be hidden in some sort of macro when I create B or b, like:
var b = macro_wrap(B("123"))
With plain var, you cannot do it.
The closest you can get is to create a getter-setter pair which will look like a var from outside:
object Stuff {
private var b0 = B("123")
def b: B = b0
def b_=(newb: B): Unit = {
b0 = newb
println(s"b is changed to $newb")
}
}
Then:
Stuff.b = B("xxx")
Will print the new value.
Note that the setter is a method named b_= which is treated somewhat specially by Scala compiler - an assignment Stuff.b = B("xxx") is automatically translated into Stuff.b_=(B("xxx")). This works only if setter is accompanied by a getter.
Related
Say I have some code of the sort:
var (nodes, d, p) = someFunction()
Then I have a few more instructions and I need to refresh the values of nodes, d and p. My current code is something like
val aux = someFunction(); nodes = aux._1; d = aux._2; p = aux._3
Which is obviously unnecessarily ugly. Ideally I'd want to do something like
(nodes, d, p) = someFunction()
Where the variables have been already declared before, but Scala doesn't allow me.
Any ideas on how to "solve" this?
You can write a helper function in the local context that takes the tuple that is returned from someFunction() and mutate needed variables.
Like this:
def someEnclosingFunctionOrCodeBlock = {
var nodes, d, p;
def mutateVars(tuple: (TypeNodes, TypeD, TypeP)): Unit = {
nodes = tuple._1
d = tuple._2
p = tuple._3
}
mutateVars(someFunction())
// ..
mutateVars(someFunction())
}
Additionally, you can fold it into 1 function that is something like callSomeFunctionAndMutateVars().
You can do it 2 ways - using the previous helper function
def callSomeFunctionAndMutateVars() = mutateVars(someFunction())
Or changing the previous helper function to
def callSomeFunctionAndMutateVars(): Unit = {
val tuple = someFunction()
nodes = tuple._1
d = tuple._2
p = tuple._3
}
PS: Honestly, you should consider changing it to immutable structures and an explicit composition of evaluations.
I have a class A in Scala, like this one:
class A {
val a = 3
lazy val b = 2
println("a = " + a)
println("b = " + b)
}
Next, I extend this class to another class B:
class B extends A {
override val a = 4
override lazy val b = 3
}
Now, when I create an object of class B, I get the following output:
a = 0 //the default value of int is zero `0` in Scala
b = 3
Whereas I was expecting the output to be:
a = 3
b = 2
My question is how do the println() functions in class A come to know about the values defined in class B, but only of b and not of a?
docs.scala-lang.org - tutorials - initialization-order provides a complete explanation.
In order to see clearer, let's print the same thing in class B as in class A:
class A {
val a = 3
lazy val b = 2
println("A: a = " + a)
println("A: b = " + b)
}
class B extends A {
override val a = 4
override lazy val b = 3
println("B: a = " + a)
println("B: b = " + b)
}
In this case, new B() produces:
A: a = 0
A: b = 3
B: a = 4
B: b = 3
The initialization order of non-lazy val variables is given by:
In the absence of “early definitions” (see below), initialization of
strict vals is done in the following order.
Superclasses are fully initialized before subclasses.
Otherwise, in declaration order.
Thus A is fully initialized before B.
But val can't be initialized more than once. So internally Scala gives it a default value (0 for an Int, null for a String, ..) when dealing first with the superclass A.
Thus it prints 0 at first (when initializing A) and then 4 (when initializing B).
Using lazy vals is the solution proposed by the scaladoc to bypass this limitation.
Why lazy val works as expected? Because val is marked by lazy will be initialized on its first access.
Why non-lazy does not work as expected? Because of initialization order.
non-lazy vals are initialized in the following order:
Superclasses are fully initialized before subclasses.
Otherwise, in declaration order.
In your example you're trying to access an override val, but an override val will appear to be null during the construction of superclasses.
Code with more logs to see an initialization order:
class A {
println("First line of A")
val strictVal: String = {
println("A.strictVal called")
"strictVal of A"
}
lazy val lazyVal: String = {
println("A.lazyVal called")
"lazyVal of A"
}
println(s"lazyVal = $lazyVal")
println(s"strictVal = $strictVal")
println("Last line of A")
}
class B extends A {
println("First line of B")
override val strictVal: String = {
println("B.strictVal called")
"strictVal of B"
}
override lazy val lazyVal: String = {
println("B.lazyVal called")
"lazyVal of B"
}
println("Last line of B")
}
Output for new B():
First line of A
A.strictVal called
B.lazyVal called
lazyVal = lazyVal of B
strictVal = null
Last line of A
First line of B
B.strictVal called
Last line of B
How does one bind a polymorphic type variable to the parameter of a unary type constructor in Scala?
def f[CollectionOfE] = new Blah[...]
{
def g(a: E) =
{ ... }
}
...
val x = f[Set[Int]] // want E above to bind to Int
Within the definition of g i wish to be able to refer to the parameter type of the collection on which f has been instantiated.
I've tried:
def f[C[E]] = new Blah[...] ...
but the scope of E seems to be local to the [ ... ], if that makes any sense...
You can do this if you define E a separate parameter. E.g.
def f[E, C <: util.Collection[E]] = new Blah {
def g(a: E) = ...
}
val x = f[Int, Set[Int]].g(1) // compiles
val y = f[Int, Set[Int]].g("string") // doesn't compile
Edit
You can make it slightly more concise by calling the function with underscore:
f[Int, Set[_]].g(1)
If I understand your intention correctly, you might want something like this:
def f[E, C[_]] = new Blah[...] {
def g(e: E) = ???
}
...
f[Int, Set]
Basically, if you want to refer to a type later, you need to put it as a separate type parameter. You might also want to limit type of C[_] to some collection.
How can I fix this code :
trait A[A,B]{
def f(a:A):B
}
trait B[A,B]{
def g(a:A):B
}
type C = A[String,Int] with B[String,Double]
//works fine
new A[String,Int] with B[String,Double] {
def f(a:String):Int = 1
def g(a:String):Double = 2.0
}
//error
new C {
def f(a:String):Int = 1
def g(a:String):Double = 2.0
}
The exception i got is :
Error:(41, 6) class type required but A$A42.this.A[String,Int] with A$A42.this.B[String,Double] found
new C {
^
Any Idea how to solve that and what is the reason for that ?
My guess why it doesn't work (and probably shouldn't): type C = ... defines something which is not a class type, I wonder what it is. But when you pass it to new it expects new class_type with trait_type ..., so you are trying to replace only one thing, namely class_type with C. If you define C without with it will work.
You can also write:
type C1 = A[String,Int]
type C2 = B[String,Double]
new C1 with C2 {
def f(a:String):Int = 1
def g(a:String):Double = 2.0
}
Minimal Working Example (Scala 2.9.2):
object Main extends App {
class A {
var a=0
}
val b = Array.fill(2)(new A)
b(1).a = 9
println(b(0).a) //prints 0
println(b(1).a) //prints 9
val a = new A
val c = Array.fill(2)(a)
c(1).a = 9
println(c(0).a) //prints 9
println(c(1).a) //prints 9
}
A related question is "Is it the same with imported Java classes?"
How can I workaround, if I need to fill an Array inside a function with copies of an instance passed as argument?
[Regarding identical copies, it was worth to me to check out the easy cloning library.
Just adding the workaround to a function call, based on answers:
class A {
var a=0
}
def f(a: => A) { // "=>" added
val b = Array.fill(2)(a)
b(1).a=9
println(b(0).a) //prints 0
println(b(1).a) //prints 9
}
f(new A)
Another way is to declare a function, not a value def a = new A:
object Main extends App {
class A {
var a=0
}
val b = Array.fill(2)(new A)
b(1).a = 9
println(b(0).a) //prints 0
println(b(1).a) //prints 9
def a = new A
val c = Array.fill(2)(a)
c(1).a = 9
println(c(0).a) //prints 0
println(c(1).a) //prints 9
}
The fill method is defined with it's second parameter as "call-by-name". This means that the passed-in block is re-evaluated for every cell in the Array. See in the definition that the type of elem is => T, not simply T:
def fill[T: ClassManifest](n: Int)(elem: => T): Array[T]
So in your first version, the block new A is re-evaluated for each cell, meaning that each cell gets a fresh A object. In the second version, new A is called only once, and that object is placed into every cell.
You can actually see this if you run on the REPL:
scala> val b = Array.fill(2)(new A)
b: Array[A] = Array(A#2049bed2, A#498edd8d) // two different objects
scala> val c = Array.fill(2)(a)
c: Array[A] = Array(A#31e0c0b6, A#31e0c0b6) // the same object repeated
Having a look at the signature of fill
def fill[T: ClassManifest](n: Int)(elem: => T)
So it gets a call-by-name argument, which means new A will be executed every time you process a cell in the array.
One fills the array with a single instance of A, the other fills the array with a new instance of A.