Superclass constructors in scala - scala

Scala's handling of superclass constructor parameters is confusing me...
with this code:
class ArrayElement(val contents: Array[String]) {
...
}
class LineElement(s: String) extends ArrayElement(Array(s)) {
...
}
LineElement is declared to extend ArrayElement, it seems strange to me that the Array(s) parameter in ArrayElement(Array(s)) is creating an Array instance - runtime??? Is this scala's syntatic sugar or is there something else going on here?

Yes, the Array(s) expression is evaluated at run-time.
class Foo (val x: Int)
class Bar (x: Int, y: Int) extends Foo(x + y)
Scala allows expressions in the calls to a superclass' constructor (similar to what Java does with its use of super(...)). These expressions are evaluated at run-time.

Actually The Array(s) is evaluated at run-time because the structure you've used is an effective call to primary constructor of your super class.
To recall, a class can only have on primary constructor that takes arguments in its definition class A(param:AnyRef), other constructors are called this and are mandate to call the primary constructor (or to chain constructors up to it).
And, such a constraint exists on super call, that is, a sub class primary constructor calls the super primary constructor.
Here is how to see such Scala structure
class Foo (val x: Int)
class Bar (x: Int, y: Int) extends Foo(x + y)
the Java counterpart
public class Foo {
private x:int;
public Foo(x:int) {
this.x = x;
}
public int getX() {
return x;
}
}
public class Bar {
private y:int;
public Bar(x:int, y:int) {
/**** here is when your array will be created *****/
super(x+y);
this.y = y;
}
public int getY() {
return y;
}
}

Related

How does the inheritance of the constructor in Scala work?

class Point(val x: Int, val y: Int) {
def this(xArg: Int) = {
this(xArg, 0)
println("constructor")
}
}
class TalkPoint(x: Int, y: Int) extends Point(x, y) {
def talk() = {
println("my position is (" + x + "," + y + ")")
}
}
object Test {
def main(args: Array[String]): Unit = {
val p = new TalkPoint(0, 0)
p.talk()
}
}
Here is an example program in Scala.
I am confused by the missing result "constructor " .
where is the constructor of the parent class Point ?
The constructor is actually part of the definition of the class:
class Point(val x:Int, val y:Int). This line defines not only Point's primary constructor that takes two Ints, by using val, it has made x and y read-only fields of the Point class. def this(xArg:Int) is what is called an auxiliary constructor, and notice how it calls the primary constructor (as all auxiliary constructors in Scala must do): this(xArg,0). In Java, Point's definition is roughly equivalent to
class Point {
public final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public Point(int x) {
this(x,0);
System.out.println("constructor");
}
}
The line class TalkPoint(x:Int,y:Int) extends Point(x,y) not only defines the class TalkPoint, it also defines its primary constructor, declares it is a subclass of Point, and even calls Point's primary constructor. In Java, something like
class TalkPoint extends Point {
public TalkPoint(int x, int y) {
super(x, y);
}
// ...
}
In your main method, you call TalkPoint's primary constructor, which in turn calls Point's primary constructor, and at no point is Point's auxiliary constructor invoked, and thus nothing is printed. Try creating a Point, however, with its auxiliary constructor: val p = new Point(42)

How to implement a single factory pattern?

I'd like to have some type 'ValidatedVals' that can be instantiated exclusively by a single class (i.e. it is the single factory for ValidatedVals).
I'd then like to reference this ValidatedVals type in many other classes.
Private constructors seems like one answer... but ...
The code below fails because (apparently) an inner class with a private constructor, declared within
object X{ ... }
makes that constructor not visible within object X
So, in the code below, how can I make it so that:
ONLY ValidatedValsFactory can construct a ValidatedVals object
AND I can reference a ValidatedVals type in other classes?
_
class ValidatedValsFactory {}
object ValidatedValsFactory {
class ValidatedVals private (val a: Int, val b: Int) {}
def validate(a: Int, b: Int): Unit = { /* .... */ }
def makeValidated(a: Int, b: Int): ValidatedVals = {
validate(a, b);
// **** Nope. Fail. Not visible. *****
return new ValidatedVals(a, b)
}
}
class ValidatedValsConsumer {
def f(param: ValidatedValsFactory.ValidatedVals): Unit = { /* ... */ }
}
I don't want f's parameter's type to be an interface (because its easy to circumvent the validate by implementing the interface).
I can't move class ValidatedVals into the class definition of ValidatedValsFactory because ValidatedValsConsumer needs to be able to reference the inner class typename (and therefore ValidatedVals must be a static declaration).
garrghh!
Looks like the compilation error goes away if you make it private to the object:
class ValidatedVals private[ValidatedValsFactory] (val a: Int, val b: Int) {}
Consider declaring your ValidatedVals type as a sealed class or trait. More details here: What is a sealed trait?

Inheritance and a constructor with a parameter

I have a class:
class BaseClass(val a: Int) {
//....
}
And a child class which can be represented by 2 ways:
class ChildClass extends BaseClass {
//...
}
or
class ChildClass(a: Int) extends BaseClass(a) {
// if I use val keyword, it doesn't change anything -- the error remains
//...
}
// the error:
//overriding value a in class BaseClass of type Int;
//[error] value a needs `override' modifier
In both cases I have an error(s) so that I can't even compile it.
How do I make it compile?
First, in your situation you can't extend your BaseClass with the construct
class ChildClass extends BaseClass {
...
}
because you are not providing an argument for BaseClass' constructor.
You should do something like:
val myVal: Int = 5;
class ChildClass extends BaseClass(myVal) {
...
}
(your latter extension form is correct, by the way).
Second (and the nature of your problem), you cannot specify the same parameter list signature for ChildClass' constructor without adding the override modifier, this way:
class ChildClass(override val a: Int) extends BaseClass(a) {
...
}
There are no problems with your code. class ChildClass(a: Int) extends BaseClass(a) works fine. The problem it somewhere else.
Declaring ChildClass as
class ChildClass(val a: Int) extends BaseClass(a)
means that you (try to) introduce the private field ChildClass.a. Since BaseClass.a is already declared, the error tells you that you need to explicitly state that you want to override BaseClass.a, i.e.,
class ChildClass(override val a: Int) extends BaseClass(a)
You can avoid this by
a) renaming the newly introduced variable, e.g.,
class ChildClass(val _a: Int) extends BaseClass(_a)
b) or by declaring, but not defining it, in BaseClass. This, however, works only if BaseClass can be abstract:
abstract class BaseClass {
def a: Int
}
class ChildClass(val a: Int) extends BaseClass

Scala's parametric fields and constructor arguments

I understand that parametric fields (like x in the example below) behave like normal fields; so you can reference them in methods:
class Test(val x: Int) { // x is a parametric field
override def toString = "Test: " + x;
}
However, if you drop the keyword val, the code still compiles (and looking and the .class output, x is still a member of the class). So I am wondering, what is the difference between parametric fields (i.e., val x: Int in the above) and constructor arguments (x: Int)?
(With Java in the back of my head, I would have expected the scope of a constructor like x to not include a method like toString.)
Without the val keyword, your code is similar to: class Test (private[this] val x: Int) { ... }. Therefore, xis available in the whole class but not from the outside.
It's not mentioned in your question but it might also be useful: in a case class the default modifier is val. Thus case class Test(x: Int) {...}is equivalent to case class (val x: Int) {...}.
A constructor parameter effectively becomes a private[this] field but only if is referenced in at least one method. Otherwise a field is not generated in the class.
For example:
class Foo(i: Int) {
println(i)
}
becomes
$ javap -private Foo
Compiled from "Foo.scala"
public class Foo extends java.lang.Object implements scala.ScalaObject{
public Foo(int);
}
But
class Bar(i: Int) {
def baz = println(i)
}
becomes
$ javap -private Bar
Compiled from "Bar.scala"
public class Bar extends java.lang.Object implements scala.ScalaObject{
private final int i;
public void baz();
public Bar(int);
}

In Scala, how do you define a local parameter in the primary constructor of a class?

In Scala, how does one define a local parameter in the primary constructor of a class that is not a data member and that, for example, serves only to initialize a data member in the base class?
For example, in the following code, how could I properly define parameter b in the primary constructor of class B so that it generates only a temporary local parameter and not a data member?
class A(var a: Int)
class B(?b?) extends A(b)
Randall, your answers explain why the Scala compiler complains when I introduce a method inc that increments the property a, but also change the name of the parameter in the class B constructor to match that of the parameter in the class A constructor:
class A(var a: Int)
class B(a: Int) extends A(a) {
def inc(value: Int) { this.a += value }
}
Scala compiler output:
$ scala construct.scala
construct.scala:3: error: reassignment to val
def inc(value: Int) { this.a += value }
^
one error found
Scala complains because class B must now have a private, read-only property a due to the reference to a in inc. Changing B(a: Int) to B(var a: Int) generates a different compiler error:
construct.scala:2: error: error overriding variable a in class A of type Int;
variable a needs `override' modifier
class B(var a: Int) extends A(a) {
^
one error found
Adding override doesn't help, either:
construct.scala:2: error: error overriding variable a in class A of type Int;
variable a cannot override a mutable variable
class B(override var a: Int) extends A(a) {
^
one error found
How can I use the same name in the parameter in the primary constructor of B as the property defined in the primary constructor of the base class A?
If you remove the "var" or "val" keyword from the constructor parameter, it does not produce a property.
Be aware, though, that non-var, non-val constructor parameters are in-scope and accessible throughout the class. If you use one in non-constructor code (i.e., in the body of a method), there will be an invisible private field in the generated class that holds that constructor parameter, just as if you made it a "private var" or "private val" constructor parameter.
Addendum (better late than never??):
In this code the references to the constructor parameter occur only in the constructor body:
class C1(i: Int) {
val iSquared = i * i
val iCubed = iSquared * i
val iEven = i - i % 2
}
... Here the value i exists only during the execution of the constructor.
However, in the following code, because the constructor parameter is referenced in a method body—which is not part of the constructor body—the constructor parameter must be copied to a (private) field of the generated class (increasing its memory requirement by the 4 bytes required to hold an Int):
class C2(i: Int) {
val iSquared = i * i
val iCubed = iSquared * i
val iEven = i - i % 2
def mod(d: Int) = i % d
}
After some experimentation, I determined that simply leaving out var or val in front of the parameter b will make it a local parameter and not a data member:
class A(var a: Int)
class B(b: Int) extends A(b)
Java expansion:
$ javap -private B
Compiled from "construct.scala"
public class B extends A implements scala.ScalaObject{
public B(int);
}
$ javap -private A
Compiled from "construct.scala"
public class A extends java.lang.Object implements scala.ScalaObject{
private int a;
public A(int);
public void a_$eq(int);
public int a();
public int $tag() throws java.rmi.RemoteException;
}
Notice that class A has a private data member a due to the var a: Int in its primary constructor. Class B, however, has no data members, but its primary constructor still has a single integer parameter.
You can create temporary variables throughout the initialization of single class members like this:
class A(b:Int){
val m = {
val tmp = b*b
tmp+tmp
}
}
Derek,
If you have this:
class A(a: Int) {
val aa = a // reference to constructor argument in constructor code (no problem)
def m: Float = a.toFloat // reference to constructor argument in method body (causes a to be held in a field)
}
you'll find (using javap, e.g.) that a field named "a" is present in the class. If you comment out the "def m" you'll then see that the field is not created.