When overriding a trait, why the value is strange? - scala

Demo scala code:
trait A {
val a = 3
val b = a + 2
}
trait B extends A {
override val a = 10
}
object X extends B
println(X.b)
It prints value: 2, why is it not 5 or 12?

To answer the why:
In Scala when you write
class A {
val a = 2
}
The value is initialized in the constructor of the class (the same behavior applies to traits and objects). Furthermore, superclasses are initialized before subclasses. This leads to the following behavior for your use case:
B is created (memory is reserved), with two variables a and b whose value is 0. Now the constructor of A is invoked. Because a is overwritten in a subclass and due to Scalas dynamic binding nature, it is not assigned with 2, but with the value of the subclass. You want to be it 10, but because this assignment happens in the constructor of B (which is not yet invoked) the default value 0 is assigned. Now, b is assigned. Because it is not overwritten, the value a+2 is chosen, where a is 0. Because the constructor of A is finished here, the constructor of B can be invoked, which assigns 10 to a.
Hence, a is 10 and b is 2.
To answer what to do against this behavior bug:
Don't use vals as long as you don't absolutely understand about the problems that can arise. Use defs or lazy vals instead, there values are not initialized in the constructor of a class and therefore can be easily overwritten. If you absolutely need a val in a trait, then make it final
It is possible to mark a var as initialization independent for the subclass, which can be done with var a: Type = _. This tells the compiler to not initialize this variable in the constructor of the defining class (but means that the value needs to stay mutable). It can then easily be assigned in the subclass. This gets important when the in the constructor of the superclass as method is called, that initializes a var:
class A {
f()
def f() = ()
}
class B extends A {
// don't initialize this var with anything else here or
// the later assignment will be overwritten
var b: Int = _
override def f() =
b = 5
}
new B().b // prints 5

Related

Strange behavior of Scala compiler when initializing a class with a lazy argument

How possible that the first is correct Scala code but the second won't even compile?
The one that does compile
object First {
class ABC(body: => Unit) {
val a = 1
val b = 2
println(body)
}
def main(args: Array[String]): Unit = {
val x = new ABC {
a + b
}
}
}
This one doesn't compile on Scala 2.11 and 2.12
object Second {
class ABC(body: => Int) {
val a = 1
val b = 2
println(body)
}
def main(args: Array[String]): Unit = {
val x = new ABC {
a + b
}
}
}
It's not strange at all. Let's look at the first example:
You declare your class ABC to receive a pass by name parameter that returns Unit and you think this snippet:
val x = new ABC {
a + b
}
is passing that body parameter, it isn't.What's really happening is:
val x = new ABC(()) { a + b }
If you run that code you will see that println(body) prints () because you're not passing a value for your body parameter, the compiler allows it to compile because as the scaladoc states there is only 1 value of type Unit:
Unit is a subtype of scala.AnyVal. There is only one value of type Unit, (), and it is not represented by any object in the underlying runtime system. A method with return type Unit is analogous to a Java method which is declared void.
Since there is only one value the compiler allows you to omit it and it will fill in the gap. This doesn't happen with singleton objects because they don't extend AnyVal. Just has the default value for Int is 0 the default value for Unit is () and because there is only this value available the compiler accepts it.
From documentation:
If ee has some value type and the expected type is Unit, ee is converted to the expected type by embedding it in the term { ee; () }.
Singleton objects don't extend AnyVal so they don't get treated the same.
When you use syntax like:
new ABC {
// Here comes code that gets executed after the constructor code.
// Code here can returns Unit by default because a constructor always
// returns the type it is constructing.
}
You're merely adding things to the constructor body, you are not passing parameters.
The second example doesn't compile because the compiler cannot infer a default value for body: => Int thus you have to explicitly pass it.
Conclusion
Code inside brackets to a constructor is not the same as passing a parameter. It might look the same in same cases, but that's due to "magic".
You cannot pass a single argument to a constructor in curly braces, because this would be parsed as defining an anonymous class. If you want to do this, you need to enclose the curly braces in normal braces as well, like this:
new ABC({
a + b
})
As for why does compiler accept new ABC {a + b}, the explanation is a bit intricate and unexpected:
new ABC {...} is equivalent to new ABC() {...}
new ABC() can be parsed as new ABC(()) because of automatic tupling, which is a feature of the parser not mentioned in the specs, see SI-3583 Spec doesn't mention automatic tupling. The same feature casues the following code to compile without an error:
def f(a: Unit) = {}
f()
def g(a: (Int, Int)) = {}
g(0,1)
Note the call produces a warning (even your original example does):
Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want.
The warning is produced since 2.11, see issue SI-8035 Deprecate automatic () insertion.

Basic Scala: Methods holding parameters?

I am reading the book Programming in Scala and in chapter 10 I had to write:
abstract class Element {
def contents: Array[String]
def height: Int = contents.length
def width: Int = if (height == 0) 0 else contents(0).length
}
class ArrayElement(conts: Array[String]) extends Element {
def contents: Array[String] = conts
}
but the concept I don't catch here is how can I define a method that is holding a variable? As far as I know, methods return a value, it can be a computed value or an instance variable directly, but they can't hold a value. Am I forgetting a basic concept about the programming language that applies here too?
Try this out:
abstract class Foo { def bar: Int }
class Baz(val bar: Int) extends Foo
In Scala, you can implement methods by creating member variables with same name and same type. The compiler then adds a corresponding getter-method automatically.
The member variable and the getter-method are still two different things, but you don't see much difference syntactically: when you try to access it, its both just foo.bar, regardless of whether bar is a method or a member variable.
In your case
def contents: Array[String] = conts
is just an ordinary method that returns an array, an equivalent way to write the same thing would be
def contents: Array[String] = {
return conts
}
Since the array is mutable, you can in principle use this method to modify entries of your array, but the method itself is really just a normal method, it doesn't "hold" anything, it just returns reference to your array.
Edit: I've just noticed that conts is actually not a member variable. However, its still captured in the definition of the contents method by the closure-mechanism.

Set a private var by an anonymous class in Scala?

I found an example about abstract type member in Odersky's paper (Chapter 2.1): http://lampwww.epfl.ch/~odersky/papers/ScalableComponent.pdf
I paste it below
abstract class AbsCell {
type T
val init: T
private var value: T = init
def get: T = value
def set(x:T):Unit = {value = x}
}
val cell = new AbsCell{ type T=Int; val init=1}
cell.set(cell.get + 1)
cell.get
The codes doesn't work as expected in the latest Scala (Scala Version: 2.11).
I found the value of the last expression cell.get is 1, while what I expected is 2. The reason is that the private var value: T = init doesn't work well for the mixin anonymous class { type T=Int; val init=1}.
Does anyone have any ideas about this?
Your code doesn't work because value is initialized before the val init is. So at the time value is initialized, init is still equal to the default value of type T, which is 0 for T = Int.
You can fix this by making init a def or a lazy val.
Note that the paper you reference does not have the code you mention. In the paper, init is a parameter to the constructor of GenCell/AbsCell, and is therefore initialized properly before value is.

Confusing construction order with lazy val

In my understanding,
When an object of subclass is created, the constructor of the subclass
first calls the constructor of parent class. In the parent
constructor, if there is a def that has been overridden then the
overridden copy is called.
Due to all this, in the following code the 'env' variable is not set to (intuitively) the correct length of 1.
class C {
val range: Int = 10
val env = new Array[Int](range)
}
class A extends C {
override val range = 1
}
val a = new A
a.env.length //0 instead of 1 or 10
Now, if we define range as a lazy val then the problem goes away and a.env.length yields 1. I am not able to understand why? (because the moment new Array[Int](range) is called, I suppose, it will call the getter for range from subclass and that will return 0.
Can someone clarify, why lazy val solves this issue.
The one-question FAQ moved to:
http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html
lazy val is on-demand initialization, whereas an "eager" val, a misnomer, waits patiently, even with indifference, for the constructor in which it is defined to be run.

Scala singleton factories and class constants

OK, in the question about 'Class Variables as constants', I get the fact that the constants are not available until after the 'official' constructor has been run (i.e. until you have an instance). BUT, what if I need the companion singleton to make calls on the class:
object thing {
val someConst = 42
def apply(x: Int) = new thing(x)
}
class thing(x: Int) {
import thing.someConst
val field = x * someConst
override def toString = "val: " + field
}
If I create companion object first, the 'new thing(x)' (in the companion) causes an error. However, if I define the class first, the 'x * someConst' (in the class definition) causes an error.
I also tried placing the class definition inside the singleton.
object thing {
var someConst = 42
def apply(x: Int) = new thing(x)
class thing(x: Int) {
val field = x * someConst
override def toString = "val: " + field
}
}
However, doing this gives me a 'thing.thing' type object
val t = thing(2)
results in
t: thing.thing = val: 84
The only useful solution I've come up with is to create an abstract class, a companion and an inner class (which extends the abstract class):
abstract class thing
object thing {
val someConst = 42
def apply(x: Int) = new privThing(x)
class privThing(x: Int) extends thing {
val field = x * someConst
override def toString = "val: " + field
}
}
val t1 = thing(2)
val tArr: Array[thing] = Array(t1)
OK, 't1' still has type of 'thing.privThing', but it can now be treated as a 'thing'.
However, it's still not an elegant solution, can anyone tell me a better way to do this?
PS. I should mention, I'm using Scala 2.8.1 on Windows 7
First, the error you're seeing (you didn't tell me what it is) isn't a runtime error. The thing constructor isn't called when the thing singleton is initialized -- it's called later when you call thing.apply, so there's no circular reference at runtime.
Second, you do have a circular reference at compile time, but that doesn't cause a problem when you're compiling a scala file that you've saved on disk -- the compiler can even resolve circular references between different files. (I tested. I put your original code in a file and compiled it, and it worked fine.)
Your real problem comes from trying to run this code in the Scala REPL. Here's what the REPL does and why this is a problem in the REPL. You're entering object thing and as soon as you finish, the REPL tries to compile it, because it's reached the end of a coherent chunk of code. (Semicolon inference was able to infer a semicolon at the end of the object, and that meant the compiler could get to work on that chunk of code.) But since you haven't defined class thing it can't compile it. You have the same problem when you reverse the definitions of class thing and object thing.
The solution is to nest both class thing and object thing inside some outer object. This will defer compilation until that outer object is complete, at which point the compiler will see the definitions of class thing and object thing at the same time. You can run import thingwrapper._ right after that to make class thing and object thing available in global scope for the REPL. When you're ready to integrate your code into a file somewhere, just ditch the outer class thingwrapper.
object thingwrapper{
//you only need a wrapper object in the REPL
object thing {
val someConst = 42
def apply(x: Int) = new thing(x)
}
class thing(x: Int) {
import thing.someConst
val field = x * someConst
override def toString = "val: " + field
}
}
Scala 2.12 or more could benefit for sip 23 which just (August 2016) pass to the next iteration (considered a “good idea”, but is a work-in-process)
Literal-based singleton types
Singleton types bridge the gap between the value level and the type level and hence allow the exploration in Scala of techniques which would typically only be available in languages with support for full-spectrum dependent types.
Scala’s type system can model constants (e.g. 42, "foo", classOf[String]).
These are inferred in cases like object O { final val x = 42 }. They are used to denote and propagate compile time constants (See 6.24 Constant Expressions and discussion of “constant value definition” in 4.1 Value Declarations and Definitions).
However, there is no surface syntax to express such types. This makes people who need them, create macros that would provide workarounds to do just that (e.g. shapeless).
This can be changed in a relatively simple way, as the whole machinery to enable this is already present in the scala compiler.
type _42 = 42.type
type Unt = ().type
type _1 = 1 // .type is optional for literals
final val x = 1
type one = x.type // … but mandatory for identifiers