Why is using uninitialized variables allowed in Scala? [duplicate] - scala

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Scala: forward references - why does this code compile?
object Omg {
class A
class B(val a: A)
private val b = new B(a)
private val a = new A
def main(args: Array[String]) {
println(b.a)
}
}
the following code prints "null". In java. similar construction doesn't compile because of invalid forward reference. The question is - why does it compile well in Scala? Is that by design, described in SLS or simply bug in 2.9.1?

It's not a bug, but a classic error when learning Scala. When the object Omg is initialized, all values are first set to the default value (null in this case) and then the constructor (i.e. the object body) runs.
To make it work, just add the lazy keyword in front of the declaration you are forward referencing (value a in this case):
object Omg {
class A
class B(val a: A)
private val b = new B(a)
private lazy val a = new A
def main(args: Array[String]) {
println(b.a)
}
}
Value a will then be initialized on demand.
This construction is fast (the values are only initialized once for all application runtime) and thread-safe.

The way that I understand it, this has to do with how the Scala classes are created. In Java, the class defined above would be initializing the variables inline, and since a had not been defined yet, it could not be compiled. However, in Scala it is more the equivalent of this in Java (which should also produce null in the same scenario):
class Omg {
private B b = null;
private A a = null;
Omg(){
b = new B(a);
a = new A();
}
}
Alternately, you could make your declaration of b lazy, which would defer setting the value until it is called (at which time a will have been set).

If this is a concern, compile with -Xcheckinit during development and iterate until the exceptions go away.
Spec 5.1 for template body statements executed in order; beginning of 4.0 for forward references in blocks.
Forward References - why does this code compile?

As #paradigmatic states, it's not really a bug. It's the initialization order, which follows the declaration order. It this case, a is null when b is declared/init-ed.
Changing the line private val b = new B(a) to private lazy val b = new B(a) will fix issue, since using lazy will delay the init. of b to it's first usage.
It's very likely that this behavior is described in the SLS.

Related

Type bounds on methods not enforced

I can't comprehend why the compiler allows for the current code.
I use phantom types to protect access to methods. Only under specific "states" should methods be allowed to be called.
In most scenarios, this invariant is indeed verified by the compilation. Sometimes however, the compiler just ignores the constraint imposed by the phantom type.
This feels like a major bug. What am I not understanding?
I tried to simplify the problem as much as possible. My use case is more complex:
class Door[State <: DoorState] private {
def doorKey: Int = 1
def open[Phatom >: State <: Closed.type]: Door[Open.type] = new Door[Open.type]
def close[Phatom >: State <: Open.type]: Door[Closed.type] = new Door[Closed.type]
}
object Door {
def applyOpenDoor: Door[Open.type] = new Door[Open.type]
def applyClosedDoor: Door[Closed.type] = new Door[Closed.type]
}
sealed trait DoorState
case object Closed extends DoorState
case object Open extends DoorState
Then
val aClosedDoor = Door.applyClosedDoor
val res1 = aClosedDoor.close // does not compile. Good!
val res2 = aClosedDoor.open.close.close // does not compile. Good!
println(aClosedDoor.open.close.close) // does not compile. Good!
println(aClosedDoor.open.close.close.doorKey) // does not compile. Good!
aClosedDoor.open.close.close.doorKey == 1 // does not compile. Good!
println(aClosedDoor.open.close.close.doorKey == 1) // compiles! WTF?
As you can see above, the client can close a closed door. In my library, the corresponding behaviour is throwing a runtime exception. (I was confident the exception was well protected and impossible to reach)
I have only been able to replicate this problem for expressions returning boolean and when this is the argument to a function (in the example, println)
I am not looking for alternative solutions as much as I am looking for an explanation as to how this can happen? Don't you agree this is a considerable flaw? Or maybe I am missing something?
Scala version: 2.13.5
Edit
After a discussion on gitter, I opened bug request # https://github.com/scala/bug
The problem does not seem to occur in scala 3.
Seems it is an bug related to usage of nullary method
def doorKey: Int = 1
if instead it is defined as nilary method
def doorKey(): Int = 1
then it works as expected
println(aClosedDoor.open.close.close.doorKey() == 1) // compiler error

Scala NullPointerException during initialization

Consider the following case (this is a simplified version of what I have. The numberOfScenarios is the most important variable here: I usually use a hardcoded number instead of it, but I'm trying to see if it's possible to calculate the value):
object ScenarioHelpers {
val identifierList = (1 to Scenarios.numberOfScenarios).toArray
val concurrentIdentifierQueue = new ConcurrentLinkedQueue[Int](identifierList.toSeq)
}
abstract class AbstractScenario {
val identifier = ScenarioHelpers.concurrentIdentifierQueue.poll()
}
object Test1 extends AbstractScenario {
val scenario1 = scenario("test scenario 1").exec(/..steps../)
}
object Test2 extends AbstractScenario {
val scenario2 = scenario("test scenario 2").exec(/..steps../)
}
object Scenarios {
val scenarios = List(Test1.scenario1, Test2.scenario2)
val numberOfScenarios = scenarios.length
}
object TestPreparation {
val feeder = ScenarioHelpers.identifierList.map(n => Map("counter" -> n))
val prepScenario = scenario("test preparation")
.feed(feeder)
.exec(/..steps../)
}
Not sure if it matters, but the simulation starts with executing the TestPreparation.prepScenario.
I see that this code contains a circular dependency which makes this case impossible in and of itself. But I get a NullPointerException on the line in AbstractScenario where identifier is being initialized.
I don't fully understand all this, but I think it has something to do with the vals being simply declared at first and the initialization does not happen until later. So when identifier is being initialized, the concurrentIdentifierQueue is not yet initialized and is therefore null.
I'm just trying to understand the reasons behind the NullPointerException and also if there's any way to get this working with minimal changes? Thank you.
NPEs during trait initialization is a very common problem.
The most robust way to resolve it is avoiding implementation inheritance at all.
if it is not possible for some reasons you can mark problematic fields lazy val or def instead of val.
You answered that yourself:
I see that this code contains a circular dependency which makes this case impossible in and of itself. But I get a NullPointerException on the line in AbstractScenario where identifier is being initialized.
val feeder = ScenarioHelpers.identifierList... calls ScenarioHelpers initialization
val identifierList = (1 to Scenarios.numberOfScenarios).toArray calls Scenarios initialization
val scenarios = List(Test1.scenario1, Test2.scenario2) calls Test1 inicialization including AbstractScenario
Here val identifier = ScenarioHelpers.concurrentIdentifierQueue.poll() ScenarioHelpers is still initializing and identifierList is null.
You have to get numberOfScenarios in noncyclic way. Personally I would remove identifierList and assign identifier other way - incrementing counter or so.

Scala and forward references [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Scala: forward references - why does this code compile?
object Omg {
class A
class B(val a: A)
private val b = new B(a)
private val a = new A
def main(args: Array[String]) {
println(b.a)
}
}
the following code prints "null". In java. similar construction doesn't compile because of invalid forward reference. The question is - why does it compile well in Scala? Is that by design, described in SLS or simply bug in 2.9.1?
It's not a bug, but a classic error when learning Scala. When the object Omg is initialized, all values are first set to the default value (null in this case) and then the constructor (i.e. the object body) runs.
To make it work, just add the lazy keyword in front of the declaration you are forward referencing (value a in this case):
object Omg {
class A
class B(val a: A)
private val b = new B(a)
private lazy val a = new A
def main(args: Array[String]) {
println(b.a)
}
}
Value a will then be initialized on demand.
This construction is fast (the values are only initialized once for all application runtime) and thread-safe.
The way that I understand it, this has to do with how the Scala classes are created. In Java, the class defined above would be initializing the variables inline, and since a had not been defined yet, it could not be compiled. However, in Scala it is more the equivalent of this in Java (which should also produce null in the same scenario):
class Omg {
private B b = null;
private A a = null;
Omg(){
b = new B(a);
a = new A();
}
}
Alternately, you could make your declaration of b lazy, which would defer setting the value until it is called (at which time a will have been set).
If this is a concern, compile with -Xcheckinit during development and iterate until the exceptions go away.
Spec 5.1 for template body statements executed in order; beginning of 4.0 for forward references in blocks.
Forward References - why does this code compile?
As #paradigmatic states, it's not really a bug. It's the initialization order, which follows the declaration order. It this case, a is null when b is declared/init-ed.
Changing the line private val b = new B(a) to private lazy val b = new B(a) will fix issue, since using lazy will delay the init. of b to it's first usage.
It's very likely that this behavior is described in the SLS.

Cannot compile file in Scala

From an example in book "Begining in Scala", the script is:
import scala.collection.mutable.Map
object ChecksumAccumulator {
private val cache=Map[String,Int]()
def calculate(s: String):Int =
if(cache.contains(s))
cache(s)
else{
val acc = new ChecksumAccumulator
for(c <- s)
acc.add(c.toByte)
val cs=acc.checksum
cache+= (s -> cs)
cs
}
}
but, when I tried to compile this file
$scalac ChecksumAccumulator.scala, then generate an error, "not found: type ChecksumAccumulator val acc = new ChecksumAccumulator", any suggest?
Thanks,
'object' keyword defines a singleton object, not a class. So you can't new an object, the 'new' keyword requires a class.
check this Difference between object and class in Scala
You probably left some code out that looks like
class ChecksumAccumulator {
//...
}
The other answers are correct in saying what the problem is, but not really helping you understand why the example from the book is apparently not correct.
However, if you look at the Artima site, you will find the example is in a file here
Your code is an incomplete fragment. The file also includes these lines
// In file ChecksumAccumulator.scala
class ChecksumAccumulator {
private var sum = 0
def add(b: Byte) { sum += b }
def checksum(): Int = ~(sum & 0xFF) + 1
}
... without which you will get the error you had.
your issue is here
val acc = new ChecksumAccumulator
you cannot use new keyword with the object.
objects cannot be re-instantiated. You always have single instance of an object in scala. This is similar to static members in java.
Your code, probably meant as a companion object. That's kinda factories in imperative languages.
Basicaly, you have object and class pair. Object (singleton in imperative langs) can't be instantiated multiple times, as people here already noted, and usually used to define some static logic. In fact, there is only one instantiation -- when you call him for the first time. But object can have compaion -- regular class, and, as I think you've missed definition of that regular class, so object can't see anyone else, but itself.
The solution is to define that class, or to omit new (but i think that would be logicaly wrong).

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