class needs to be abstract since its members are not instantiated - scala

I am trying to create a class rat having parameters "value" and "dimensions". Rat has a member "fitness". I want this member to be initialized by constructor, but declaring this member enforces it to be explicitly instantiated.
This is a class rat having a member fitness. I have declared but not defined the member as I want to get it through constructor.
class rat(value:Int,dimensions:Int){
var fitness:Int
def rat(){
fitness=sol_fit()
}
def sol_fit():Int={
var f=value*dimensions
f
}
}

This looks like a really bad design for a class. I question nearly everything about it. But it's easy enough to make it compile: just give the var a default value.
var fitness:Int = _
Now it compiles but the value of fitness will remain at default (0 in this case) because you have defined the method to calculate the proper fitness value but it is never invoked so the fitness value is unchanged.
But really, why go through all the rigamarole? Why not just initialize it with the calculated value? Why not var fitness:Int = sol_fit() or simply var fitness:Int = value*dimensions?

The constructor is the block following the class declaration, so it is OK to write this:
class rat(value: Int, dimensions: Int) {
val fitness: Int = value*dimensions
}
The expression value*dimensions will be computed when an instance of the class is created, and placed in the class memory as an Int value. When the fitness member is accessed, the value will be retrieved from the class memory and returned; it will not be re-computed.
If fitness had been declared using def rather than val, then the expression would be computed each time fitness was accessed.
If fitness had been declared using var then the value could be replaced with a new value, and any subsequent access to fitness would return the new value.

Related

Why is an array of a value classes compiled to an array of objects?

As I understand, if you create an array of a value class, you're actually creating an array of objects rather than the wrapped primitive. What's the reason behind this?
source:
class Wrapper(val underlying: Int) extends AnyVal
class Main {
val i: Int = 1
val w: Wrapper = new Wrapper(1)
val wrappers = Array[Wrapper](new Wrapper(1), new Wrapper(2))
val ints = Array[Int](1, 2)
}
javap output:
public class Main {
public int i();
public int w();
public Wrapper[] wrappers(); // <----why can't this be int[] as well
public int[] ints();
public Main();
}
One of the constraints of value classes is that x.isInstanceOf[ValueClass] should still work correctly. Where correctly means: transparently, without the programmer having to be aware when values may or may not be boxed.
If an Array[Meter] would be represented as an Array[Int] at runtime the following code would not work as expected, because the information that the ints in the array are actually meters is lost.
class Meter(val value: Int) extends AnyVal
def centimeters[A](as: Array[A]) = as.collect{ case m: Meter => m.value * 100 }
Note that if you have val m = new Meter(42); m.isInstanceOf[Meter] then the compiler knows that m is a Meter even though it's an Int at runtime and he can inline the isInstanceOf call to true.
Also note that this wouldn't work for arrays. If you would box the values in the array on demand you'd have to create a new array, which wouldn't be transparent to the programmer because arrays are mutable and use reference equality. It would also be a disaster for performance with large arrays.
According to https://docs.scala-lang.org/overviews/core/value-classes.html:
Allocation Summary
A value class is actually instantiated when:
a value class is treated as another type.
a value class is assigned to an array.
doing runtime type tests, such as pattern matching.
[...]
Another situation where an allocation is necessary is when assigning
to an array, even if it is an array of that value class. For example,
val m = Meter(5.0)
val array = Array[Meter](m)
The array here contains actual Meter instances and not just the underlying double primitives.
This has probably something to do with type erasure, or simply because you're creating an array of a specific type, which doesn't allow one type to be treated as another. In any case, it's a technical limitation.

When overriding a trait, why the value is strange?

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

Scala inheritance with a abstract class

I am new to scala, just doing some practice;
I tried a very simple program, briefed as following:
abstract class Device(val cds: Array[Char]) {
var codes = Array[Char](cds: _*)
def encrpt(code: Char): Char
var nextDevice: Device
def setNext(next: Device):Unit = {
nextDevice = next
}
}
//compiler error shows here
class Input(codes: Array[Char]) extends Device(codes) {
override def encrpt(code: Char) = code
}
you could see there is a compiler error at line 21, following is the message:
class Input needs to be abstract, since variable nextDevice in class Device of type com.me.acm.problem1009.Device is not
defined (Note that variables need to be initialized to be defined)
I am pretty confusing that error, my understanding, define some variable and an setter method in the parent class, so the child classes can use it without define it again. it is straight forward.
I guess I missed something. Could someone explain it to me and tell what is the correct way? thanks.
In Scala, variables do not have assumed default values as they do in Java (or many other languages). Thus, when you declare a variable, you must always specify its initial value.
In your code, you declare a variable nextDevice, but you do not give it a value. Since Scala always needs a value, it interprets what you've written as nextDevice being an abstract field, so the compiler is telling you that it must be overridden.
If you change that line to the following, for example, to specify an initial value, then the error will disappear:
var nextDevice: Device = new Input(Array())
As the error message is telling you, the variable nextDevice needs to be initialized in the constructor on Input.
class Input(codes: Array[Char]) extends Device(codes) {
override def encrpt(code: Char) = code
nextDevice = null
}
Note that using null is frowned upon in Scala. You should probably change the type of your variable to Option[Device]

Scala class constructor local parameters

Can I pass arguments to Scala class constructor that are not stored into class itself?
I want to achieve functionality which in Java could be written as follows:
class A {
private final SomethingElse y;
public A(Something x) {
y = x.derive(this);
}
}
I.e. class constructor takes parameter that is later transformed to another value using reference to this. The parameter is forgotten after constructor returns.
In Scala I can do:
class A(x: Something) {
val y = x.derive(this)
}
But it means that x is stored in the class, which I want to avoid. Since x.derive method uses reference to this, I can not make the transformation in companion object.
But it means that x is stored in the class, which I want to avoid.
If you don't reference constructor argument anywhere except the constructor itself, field won't be created. If you reference x e.g. in toString(), Scala will automatically create and assign private val for you.
Use javap -c -private A to verify what kind of fields are actually created.
BTW you pass this inside a constructor, which means a.derive() gets a reference to possibly non-initialized instance of A. Be careful!

Scala class members and constructor parameters name clash

Consider the following class written in Java:
class NonNegativeDouble {
private final double value;
public NonNegativeDouble(double value) {
this.value = Math.abs(value);
}
public double getValue() { return value; }
}
It defines a final field called value that is initialized in the constructor, by taking its parameter called alike and applying a function to it.
I want to write something similar to it in Scala. At first, I tried:
class NonNegativeDouble(value: Double) {
def value = Math.abs(value)
}
But the compiler complains: error: overloaded method value needs result type
Obviously the compiler thinks that the expression value inside the expression Math.abs(value) refers to the method being defined. Therefore, the method being defined is recursive, so I need to state its return type. So, the code I wrote does not do what I expected it to do: I wanted value inside Math.abs(value) to refer to the constructor parameter value, and not to the method being defined. It is as if the compiler implicitly added a this. to Math.abs(this.value).
Adding val or var (or private ... variants) to the constructor parameter doesn't seem to help.
So, my question is: can I define a property with the same name as a constructor parameter, but maybe a different value? If so, how? If not, why?
Thanks!
No, you can't. In Scala, constructor parameters are properties, so it makes no sense to redefine them.
The solution, naturally, is to use another name:
class NonNegativeDouble(initValue: Double) {
val value = Math.abs(initValue)
}
Used like this, initValue won't be part of the instances created. However, if you use it in a def or a pattern matching declaration, then it becomes a part of every instance of the class.
#Daniel C. Sobral
class NonNegativeDouble(initValue: Double) {
val value = Math.abs(initValue)
}
your code is right, but "constructor parameters are properties",this is not true.
A post from the official site said,
A parameter such as class Foo(x : Int) is turned into a field if it is
referenced in one or more methods
And Martin's reply confirms its truth:
That's all true, but it should be treated as an implementation
technique. That's why the spec is silent about it.
So normally, we can still treat primary constructor parameters as normal method parameter, but when the parameters is referenced by any of the methods, the compiler will cleverly turn it into a private field.
If any formal parameter preceded by the val, the compiler generates an getter definition automatically.if var, generates a setter additionally. see the language speification section 5.3.
That's all about primary constructor parameters.
You can consider parametric field
class NonNegativeDouble(val value: Double, private val name: String ){
if (value < 0) throw new IllegalArgumentException("value cannot be negative")
override def toString =
"NonNegativeDouble(value = %s, name = %s)" format (value, name)
}
val tom = "Tom"
val k = -2.3
val a = new NonNegativeDouble(k.abs, tom)
a: NonNegativeDouble = NonNegativeDouble(value = 2.3, name = Tom)
a.value
res13: Double = 2.3
a.name
<console>:12: error: value name in class NonNegativeDouble cannot be accessed in NonNegativeDouble
a.name
val b = new NonNegativeDouble(k, tom)
java.lang.IllegalArgumentException: value cannot be negative
...
It's defines fields and parameters with the same names "value", "name".
You can add modifiers such as private ...
In the case of case classes it should be:
case class NonNegativeDouble(private val initValue: Double) {
val value = Math.abs(initValue)
def copy(value: Double = this.value) = NonNegativeDouble(value)
}
The implementation of copy is required to prevent the sintesized version of the compiler that will bind the initValue argument.
I expect that the compiler is smart enough to not retain the «extra space» for the initValue. I haven't verified this behaviour.