Scala - Making sure that a field from the superclass is used - scala

In Scala, fields are declared in the primary constructor. And, if it happens to have the same name as a field from the super class, it will use the one passed in instead, which is what I am trying to avoid. Take the following example:
class Parent(protected val changedParam: MyClass)
class Child(changedParam: MyClass) extends Parent(doStuff(changedParam)) {
def foo() = {
bar(changedParam) // Uses Child.changedParam, not Parent.changedParam, which is what I want
}
}
I want to make changedParam in Child to refer to the changedParam in Parent, not Child. Is there any way to do that?

A parameter of a class is visible in its body. It will be made a private val if need be, that is if it is used in a method, and not just in the initialization code (and of course if it is not directly declared a val with a different visibility, or a var).
So changedParam in Child shadows the one in Base. The obvious way to avoid that is simply to call it another name:
class Child(anotherName: MyClass) extends Base(doStuff(anotherName)) {...

This is considered brittle and annoying.
You get a little relief if you're shadowing a var:
scala> class A { var a = 1 } ; class B(a: Int) extends A { def f = a }
defined class A
defined class B
scala> val b = new B(42) ; b.a = 7 ; b.f
b: B = B#1376c05c
b.a: Int = 7
res0: Int = 42
scala> :replay -Xlint
Replaying: class A { var a = 1 } ; class B(a: Int) extends A { def f = a }
<console>:7: warning: private[this] value a in class B shadows mutable a inherited from class A. Changes to a will not be visible within class B - you may want to give them distinct names.
class A { var a = 1 } ; class B(a: Int) extends A { def f = a }
^
defined class A
defined class B
Replaying: val b = new B(42) ; b.a = 7 ; b.f
b: B = B#f2ff811
b.a: Int = 7
res0: Int = 42
Normally, shadowing a val is more benign, but a warning for your example would be useful.

class Parent(protected val changedParam: MyClass)
trait Child extends Parent {
def foo() = {
bar(changedParam)
}
}
object Child {
def apply(changedParam: MyClass): Child =
new Parent(doStuff(changedParam)) with Child
}
Not much to say... Turning Child into a trait avoids to declare a new temporary member that you don't want to be used after the initialization. Then I used the companion object to declare the constructor. The only difference in usage is that you don't have to add the new keyword to instanciate Child.
Test:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Parent(protected val changedParam: Int)
trait Child extends Parent {
def foo() = {
println(changedParam)
}
}
object Child {
def apply(changedParam: Int): Child =
new Parent(1 + changedParam) with Child
}
// Exiting paste mode, now interpreting.
defined class Parent
defined trait Child
defined object Child
scala> Child(42).foo()
43

1) Using explicit call to Parent with asInstanceOf:
package demo {
// remove protected or make it protected[demo]
class Parent(protected[demo] val changedParam: MyClass)
class Child(changedParam: MyClass)
extends Parent(doStuff(changedParam)) {
def foo() = {
bar(this.asInstanceOf[Parent].changedParam)
}
}
}
2) Using early initializers syntax:
class Parent(protected val changedParam: MyClass)
class Child(changedParam: MyClass) extends {
val superChangedParam = doStuff(changedParam)
} with Parent(superChangedParam) {
def foo() = {
bar(superChangedParam)
}
}
Nevertheless the best solution is to give a different name to your param.

Related

Disambiguate constructor parameter with same name as class field of superclass

When playing around with Scala I had a code like this:
class Superclass(var i : Int){}
class Subclass(i : Int) extends Superclass(0) {
print(i)
}
I found out that print(i) prints the constructor parameter i of Subclass(i : Int)
Now, my question is: in a situation like this, how do I access the field i of Superclass?
Type ascription can up-cast the type of this which effectively disambiguates the two identifiers
class Subclass(i : Int) extends Superclass(0) {
print((this: Superclass).i)
print(i)
}
As a side-note, there also exists the following syntax that could be used in the case of method members (and which perhaps is not well-known)
super[ClassQualifier]
For example, consider the following
trait A {
def f = "A"
}
trait B extends A {
override def f = "B"
}
class C extends A with B {
println(super[A].f)
println(super[B].f)
println(f)
override def f = "C"
}
new C
// A
// B
// C
#MarioGalic answered this question. I'll just make some additions that are too long for comments.
Common misunderstanding is that i in
class MyClass(i : Int)
is just a constructor parameter and not a field. Actually if we do
import scala.reflect.runtime.universe._
println(reify{
class MyClass(i : Int)
}.tree)
we'll see (Scala 2.13.2)
{
class MyClass extends AnyRef {
<paramaccessor> private[this] val i: Int = _;
def <init>(i: Int) = {
super.<init>();
()
}
};
()
}
So a parameter of primary constructor without val/var generates private[this] field. So
class MyClass(i : Int)
is similar to
class MyClass(private[this] val i : Int)
and NOT similar to Java's
public class MyClass {
public MyClass(int i) {
}
}
without fields.
We can check that i is a field referring to it with this inside class body
class MyClass(i : Int) {
println(this.i)
}
new MyClass(1) // prints 1
The field i is private[this] so we can't refer it outside the class body (or inside the body on instance different than this)
class MyClass(i : Int) {
//println(new MyClass(2).i) //doesn't compile
}
//new MyClass(1).i //doesn't compile
I didn't find proper place in Scala specification but such behavior is well-known for a long time. For example in "Scala for the impatient" by Cay S. Horstmann it's written (edition 2, section 5.7):
Construction parameters can also be regular method parameters, without val or var. How these parameters are processed depends on their usage inside the class.
If a parameter without val or var is used inside at least one method, it becomes a field. For example,
class Person(name: String, age: Int) {
def description = name + " is " + age + " years old"
}
declares and initializes immutable fields name and age that are object-private. Such a field is the equivalent of a private[this] val field (see Section 5.4,“Object-Private Fields,” on page 56).
Otherwise, the parameter is not saved as a field. It’s just a regular parameter that can be accessed in the code of the primary constructor. (Strictly speaking, this is an implementation-specific optimization.)
Actually in 2.13.2 I can't confirm the second case.
Now let's have two classes.
Scala doesn't allow
class Superclass {
val i: Int = 1
}
class Subclass extends Superclass {
//val i: Int = 2 //doesn't compile
}
unless we add override
class Superclass {
val i: Int = 1
}
class Subclass extends Superclass {
override val i: Int = 2
}
But if Superclass's field is private[this] everything is ok without override
class Superclass {
private[this] val i: Int = 1
}
class Subclass extends Superclass {
val i: Int = 2
}
Actually if we try to add override this will not compile.
The reason is this being not overriding. One of fields is private[this] i.e. not accessible outside the object where the field is defined in, so these are just two different fields:
class Superclass {
private[this] val i: Int = 1
}
class Subclass extends Superclass {
val i: Int = 2
println(this.i) // or just println(i)
// println((this: Superclass).i) //doesn't compile
}
new Subclass
//2
or
class Superclass {
val i: Int = 1
}
class Subclass extends Superclass {
private[this] val i: Int = 2
println(this.i) // or just println(i)
println((this: Superclass).i)
}
new Subclass
//2
//1
So in our case
class Superclass(var i : Int)
class Subclass(i : Int) extends Superclass(0)
are like
class Superclass extends AnyRef {
var i: Int = _
def this(_i: Int) = {
super() //pseudocode
i = _i
}
}
class Subclass extends Superclass {
private[this] val i: Int = _ //pseudocode
def this(_i: Int) = {
super(0) //pseudocode
i = _i //pseudocode because "i" is a val -- well, compiler can do things that we can't do in source code
}
}
Inside Subclass this.i or just i refers to Subclass's field private[this] val i: Int and (this: Superclass).i refers to Superclass's field var i: Int.
Do scala constructor parameters default to private val?
Scala Constructor Parameters
https://www.scala-lang.org/old/node/8384.html

Trouble with overriding a variable in abstract class

I'm new to scala and have the following question about overriding a variable in an abstract class.
abstract class ExampleClass1 {
val testVar = (i: String) => {
i + " A"
}
def exampleMethod1() = {
print testVar
}
}
object ExampleObject1 extends ExampleClass1 {
def getExampleValue() = {
exampleMethod1()
}
}
ExampleClass1 and ExampleObject1 are in one module. My module is calling ExampleObject1.getExampleValue. I want to change the behavior of testVar in ExampleClass1. Is it possible to do this without changing ExampleObjectt1?
Thank you
If you want to change a value after the class is instantiated, then you should use var instead of val, but without any further information it seems that there is a flaw in your design.
If you want to set the value of the given string on object creation, you can use something like this:
scala> abstract class ExampleClass1(val i: String)
defined class ExampleClass1
scala> object ExampleObject1 extends ExampleClass1("A")
defined object ExampleObject1
scala> ExampleObject1.i
res1: String = A
Or if you want to use given string as a parameter:
scala> abstract class ExampleClass2 {
| def test(i: String) = i + " A"
| }
defined class ExampleClass2
scala> object ExampleObject2 extends ExampleClass2
defined object ExampleObject2
scala> ExampleObject2.test("B")
res2: String = B A
What is your goal?

Conditioning on type parameters passed to a class

Suppose I have MyCoolClass which accepts a type parameter T.
Depending on T we want to define aFun in this way:
If ( T is the same type as B ) aFun should be set to () => new B
else If ( T is the same type as C ) aFun should be set to () => new C
otherwise show an error.
class MyCoolClass[T]{
def aFun = ... // fill this part
}
class A {
// something here
}
class B extends A {
// something more here
}
class C extends A {
// yet more things here
}
How would you go about doing this?
You can't do that this way. What you can do is instead restrict Ts in MyCoolClass to require a instance of a type class that would know how to instantiate T:
trait Cons[T] { def cons:T }
class MyCoolClass[T](implicit ev:Cons[T]) {
def aFun = ev.cons
}
Now what we need is define A and B and Cons[A] and Cons[B] (**)
class A
class B
object A { implicit def consA:Cons[A] = new Cons[A] { def cons = new A } }
object B { implicit def consA:Cons[B] = new Cons[B] { def cons = new B } }
Now in the REPL:
scala> new MyCoolClass[A].aFun
res0: A = A#1521d074
scala> new MyCoolClass[B].aFun
res1: B = B#19cdb1cb
(**) If you happen to try that in the REPL remember to copy and paste it in a :paste command, otherwise object A and B won't really be companion objects and this own't work

Scala: access "static" member of bounded generic type

I want to achieve the following:
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[T <: Super] {
def test = T.typeSpecific
}
val testerA = new Tester[SubA]
val testerB = new Tester[SubB]
testerA.test // should return 1
testerB.test // should return 2
Is something like this possible in Scala? This fails because the value of T is not found in Tester.test.
typeSpecific is not a static member, it belongs to instances of SubA and SubB, which you don't have. You also can't statically access anything from a type parameter (it's a type, not an object).
This won't work as is, because you don't have instances of SubA and SubB, nor can you obtain them via new Tester[SubA]. But you can require that Tester mixes in a type of Super in order to make it one (and thus have typeSpecific). This would require you change Super, SubA, and SubB to traits, and would also make your instance anonymous classes.
trait Super {
def typeSpecific: Int
}
trait SubA extends Super {
def typeSpecific = 1
}
trait SubB extends Super {
def typeSpecific = 2
}
// The self-type `this: A =>` requires the mix-in.
class Tester[A <: Super] { this: A =>
def test = typeSpecific
}
val testerA = new Tester[SubA] with SubA
val testerB = new Tester[SubB] with SubB
scala> testerA.test
res2: Int = 1
scala> testerB.test
res3: Int = 2
You could also require A <: Super as a constructor parameter for Tester, which is probably the cleaner option.
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[A <: Super](s: A) {
def test = s.typeSpecific
}
val testerA = new Tester(new SubA)
val testerB = new Tester(new SubB)
scala> testerA.test
res5: Int = 1
scala> testerB.test
res6: Int = 2
Any way you cut it, you're going to need an instance of SubA or SubB.
You're going to have to use reflection combined with typeTags to get your desired result. I warn you, it's somewhat ugly:
import scala.reflect.runtime.universe._
abstract class SuperClass {
def typeSpecific: Int
}
class SubA extends SuperClass {
def typeSpecific = 1
}
class SubB extends SuperClass {
def typeSpecific = 2
}
class Tester[T <: SuperClass: TypeTag] {
def test = typeTag[T].mirror.runtimeClass(typeOf[T]).newInstance.asInstanceOf[T].typeSpecific
}
I also feel I should mention that typeSpecific is not static as it is part of a class, in scala static members are defined in objects/companion objects only. Using objects it would be cleaner to do something like this:
trait SuperTrait {
def typeSpecific: Int
}
object SubA extends SuperTrait {
def typeSpecific = 1
}
object SubB extends SuperTrait {
def typeSpecific = 2
}
class Tester(testObject : SuperTrait) {
def test = testObject.typeSpecific
}
new Tester(SubA).test
new Tester(SubB).test

scala: override implicit var in constructor, in both parent class and child class?

i have a class that takes an implicit parameter which is used by functions called inside class methods. i want to be able to either override that implicit parameter and have both the class and its inherited parent class have a reference to the same new implicit object.
making the Parent implicit a var and setting that to a new value successfully overrides the implicit in the parent, but not the child.
(this is similar to scala: override implicit parameter to constructor, except there is the added restriction that the override affect both child class and parent class.)
for example:
def outside(implicit x: Boolean) {
println(x)
}
class Parent(implicit var x: Boolean) {
def setImplicit() {
x = true
}
def callOutside {
outside
}
}
class Child(implicit x: Boolean) extends Parent {
override def callOutside {
outside
}
}
and then:
scala> val a = new Parent()(false)
a: Parent = Parent#c351f6d
scala> a.callOutside
false
scala> a.setImplicit()
scala> a.callOutside
true // <-- sees the new implicit correctly
scala> val b = new Child()(false)
b: Child = Child#68331dd0
scala> b.callOutside
false
scala> b.setImplicit()
scala> b.callOutside
false // <-- wrong, desire "true" instead
is there any way to get the desired behavior? doing things like making both Parent and Child implicit be a var doesn't seem to work. thanks!
You could just
class Parent(x0: Boolean) {
implicit var x = x0
...
}
if you didn't really need the class parameter to be implicit. I'll assume that you do.
One alternative is to put the implicits on the companion object. Like so:
class Parent(x0: Boolean) {
implicit var x = x0
def setImplicit { x = true }
def outsideCall { outside }
}
object Parent {
def apply(implicit x: Boolean) = new Parent(x)
}
class Child(x0: Boolean) extends Parent(x0) {
def callOutside { outside }
}
object Child {
def apply(implicit x: Boolean) = new Child(x)
}
Alternatively, you could create a private main constructor for Child (decorated in some way so it's not ambiguous with the implicit) and use an implicit on a secondary constructor:
class Child private (b: Boolean, u: Unit) extends Parent()(b) {
def this()(implicit x: Boolean) = this(x,())
def callOutside { outside }
}