Scala's parametric fields and constructor arguments - scala

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);
}

Related

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?

underscore "class needs to be abstract since method is not defined" error

With scala 2.10.2, I have a code that extends from class scala.swing.ListView[SomeClass] and I get this error:
src/some.scala:100: error: class Some_Renderer needs to be abstract, since method componentFor in class Renderer of type (list: scala.swing.ListView[_ <: SomeClass], isSelected: Boolean, focused: Boolean, a: SomeClass, index: Int)scala.swing.Component is not defined
private class Some_Renderer extends ListView.Renderer[SomeClass]
EDIT: "an extra Note" is actually the error here, as commented B[String] must be B[_].
EDIT: some real example follows
I have reproduced it as the following example, though with an extra Note:
scala> class B[A] { val m : Int = 0 }
defined class B
scala> abstract class C[A] { def f(l: B[_]):Int }
defined class C
scala> private class D extends C[String] { def f(l: B[String]):Int = { l.m } }
<console>:9: error: class D needs to be abstract, since method f in class C of type (l: B[_])Int is not defined
(Note that B[_] does not match B[String]: their type parameters differ)
private class D extends C[String] { def f(l: B[String]):Int = { l.m } }
EDIT: MWE
import scala.swing.{Component, Label, ListView}
class Test
object Retn extends Label { opaque = false }
private class TestRenderer extends ListView.Renderer[Test]
{
def componentFor(list: ListView[_], isSelected: Boolean, focused: Boolean, test: Test, index: Int): Component =
{
val retn = Retn
retn
}
}
<console>:9: error: class TestRenderer needs to be abstract, since method componentFor in class Renderer of type (list: scala.swing.ListView[_ <: Test], isSelected: Boolean, focused: Boolean, a: Test, index: Int)scala.swing.Component is not defined
private class TestRenderer extends ListView.Renderer[Test]
^
EDIT: MWE
I am only trying to patch that line of code, and do scala programming by no means.
Yet I do not understand what is the problem with this example. I found similar questions
but not with this underscore ("_") thing.
The example tries to provide an implementation for the abstract method f from class C[A].
Thank s for your comments or answers about this issue.
B[_] is an "existential type", but you can understand this as being roughly equivalent to B[Any].
The error message tells you Note that B[_] does not match B[String]: their type parameters differ. You wouldn't expect to be able to replace a List[Any] parameter with a List[String] in an overridden definition, would you? Because then what happens when you pass it a List[Int], which is also a bona fide List[Any] as required in the abstract class?
Solution: replace def f(l: B[String]):Int = ... with def f(l: B[_]):Int = ...
Edit: the problem with your MWE is that you've defined the TestRenderer class on one line, then you've written a code block delimited by { } on the next... this will be interpreted as you intend in normal code (although it's better to put the { at the end of the previous line) but since you're in the REPL the class definition is interpreted as soon as you hit return. Solution: either put the { at the end of the private class ... line or type in :paste to allow you to write the lot before it's interpreted.
... at least, I assume that's what your problem is. The MWE works fine for me in scala 2.10.0 REPL, although I get a slightly different error message if I just type in the private class ... line.
I'm not sure what the constraints are in your original case, but in your example, could you use B[_] instead of B[String] when you override f?
class D extends C[String] { def f(l: B[_]):Int = { l.m } }
The underscore in this case is an existential type, and can can be any subtype of Any. See here for more information on existential types in Scala.

Why am I able to use the parameters passed to the class definition?

I'm just learning about classes and objects and Scala, and yesterday I saw something like this:
class Foo(bar: Int) {
def increaseByOne = bar + 1
}
Why am I able to use bar in method increaseByOne? I would expect the the method definition complain about not knowing bar.
I though the right way to define such a class would be
class Foo(x: Int) {
val bar = x
def increaseByOne = bar + 1
}
That's one of the wonderful features of Scala: if you reference constructor argument from any method that is not a constructor, Scala will automatically assign that constructor variable to a field. So effectively Scala translates your first code snippet into the second one for you (with private[this] modifier).
Moreover, preceding constructor argument with val/var will create getters/setters as well:
class Foo(val bar: Int)
val foo = new Foo(42);
println(foo.bar)
In this case bar is defined as private[this] and can be acessed within the class definition. You can check it with -Xprint:typer option:
class Foo extends java.lang.Object with ScalaObject {
<paramaccessor> private[this] val bar: Int = _;
def this(bar: Int): $line1.$read.$iw.$iw.Foo = {
Foo.super.this();
()
}
}

Superclass constructors in 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;
}
}

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.