Inheritance and a constructor with a parameter - scala

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

Related

Scala: Return type of abstract method

I cannot figure out how to specify the return type of a method an abstract class A, if the same method of the concrete classes have different return (sub)types:
abstract class A {
def method: List[Common (?)] // I want to force all subclasses to define this method
}
class B1 extends A {
def method(a,b,c): List[Sub1] = {...}
}
class B2 extends A {
def method(a,b,c): List[Sub2] = {...}
}
I tried to define a common trait of Sub1 and Sub2:
abstract class Common // or abstract class
case class Sub1 extends Common
case class Sub2 extends Common
but I keep getting this:
Compilation error[class B1 needs to be abstract,
since method "method" in class A of type => List[Common] is not defined]
If I don't define the return type in class A, I get the same error with ... type => Unit ... instead.
How can I solve that?
def method: List[Common]
Is not the same as
// returns `List[Common]` to simplify things, but it would be the same if we returned a sub-type
def method(a: ?, b: ?, c: ?): List[Common] = {...}
The first is a parameterless method that returns a List[Common], and the second is a method with three parameters that returns a List[Common]. The compiler sees these as two completely different methods. The fact that they have the same name means nothing.
The compiler is complaining because def method: List[Common] is not defined in the subclasses of A.
This compiles:
abstract class Common // or abstract class
case class Sub1() extends Common
case class Sub2() extends Common
abstract class A {
def method(): List[Common]
}
class B1 extends A {
def method(): List[Sub1] = ???
}
class B2 extends A {
def method(): List[Sub2] = ???
}
All I have done is:
add the () to Sub1() and Sub2()
return List[Common] from A
EDIT
As #m-z mentioned, it works because every def method() has the same signature now.

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?

Access a field created by the constructor in an abstract class (Scala)

I have an abstract class that implements one method.
How can I access the parameter internalValue (set by the abstract class constructor?)
abstract class Value(internalValue:Int) {
def equal( v:Value ): Boolean
def notEqual( v:Value ): Boolean = {
//here I get an error on v.internalValue:
//"value internalValue is not a member of Value"
(internalValue != v.internalValue)
}
}
case class Value1(internalValue:Int) extends Value(internalValue){
def equal( v:Value1 ): Boolean = {
//this works correctly
(internalValue == v.internalValue)
}
}
Thank you.
Define internalValue to be val:
abstract class Value(val internalValue: Int)
or if you are concerned about encapsulation (which the name internalValue suggests) you can use private val:
abstract class Value(private val internalValue: Int)
Not declaring any modified at all is effectively equivalent (?) similar to private[this] which means: only this particular instance of Value can access this private field.

Can I provide a default value for an abstract type in Scala?

I have a class like this:
abstract class CrudResource extends Controller {
type ResourceIdType
def getAction(id: ResourceIdType) = ...
def deleteAction(id: ResourceIdType) = ...
...
}
which is intended to be used like so:
class Payees extends CrudResource {
type ResourceIdType = Int
...
}
I'd like to default the ResourceIdType to Int, like so:
abstract class CrudResource extends Controller {
type ResourceIdType = Int
...
}
so that the ID type will be Int unless a subclass overrides it like so:
override type ResourceId = String
but this fails to compile with:
error: overriding type ResourceIdType in class CrudResource, which equals Int;
type ResourceIdType has incompatible type
class Payees extends CrudResource { override type ResourceIdType = String }
Is it possible to do what I'm trying to do? I tried, in CrudResource, type ResourceIdType <: Any = Int, but that's not valid syntax.
That would be a violation of the liskov substitution principle. Let's assume you can do it.
abstract class CrudResource extends Controller {
type ResourceIdType = Int
def resources: List[ResourceIdType] = ???
def getAction(id: ResourceIdType) = ???
def deleteAction(id: ResourceIdType) = ???
}
class Payees extends CrudResource {
override type ResourceIdType = String
}
class Trouble {
var resource: Controller.ResourceIdType
}
val trouble = new Trouble
val crudResource: CrudResource = new Payee
trouble.resource = crudResource.resources.head // assigning String to Int var!
However, you are halfway to a cake pattern. If you define ResourceId as an abstract nested class, you could have subclasses implementing them in terms of Int or String, as long as its API doesn't expose the specific types.
Not sure if you can really do this, but generics and inheritance can do it in a nice way:
abstract class CrudController [T] {
def getAction( resource : T )
def deleteAction( resource : T )
def updateAction( resource : T )
}
abstract class IntCrudController extends CrudController [Int]
class PayeesController extends IntCrudController {
override def getAction( resource : Int ) {}
def deleteAction(resource: Int) {}
def updateAction(resource: Int) {}
}
No, as far as I know, this isn't possible.
Scala's abstract type become frozen once you define it. You can't override one type with another in a inherited class

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.