Disambiguate constructor parameter with same name as class field of superclass - scala

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

Related

private[this] Vs giving parameters without val/var in scala

I understand that marking a val/var as private[this] inside a class and providing a class parameter without val/var is same.
class ABC (x:Int){..}
class ABC {
private[this] x:Int = 100
}
In both the cases, x can be accessed by only the constructors and the methods of the same object. Is my understanding correct ?
Thanks!
Both
import scala.reflect.runtime.universe._
reify{
class ABC(x: Int)
}.tree
and
reify {
class ABC(private[this] val x: Int)
}.tree
produce
{
class ABC extends AnyRef {
<paramaccessor> private[this] val x: Int = _;
def <init>(x: Int) = {
super.<init>();
()
}
};
()
}
And
reify{
class ABC {
private[this] val x: Int = 100
}
}.tree
produces
{
class ABC extends AnyRef {
def <init>() = {
super.<init>();
()
};
private[this] val x: Int = 100
};
()
}
So the answer to your question
In both the cases, x can be accessed by only the constructors and the methods of the same object.
is positive.
You can check that class ABC(x: Int) does create a (private[this]) field verifying that you can access it with this
class ABC(x: Int) {
this.x
}
But it's important to emphasize that Scala specification doesn't specify either that x in class ABC(x: Int) is a field or that it's not a field. This is just current behavior of Scalac and Dotty compilers.
Get the property of parent class in case classes
Disambiguate constructor parameter with same name as class field of superclass
Do scala constructor parameters default to private val?
Scala Constructor Parameters
I understand that marking a val/var as private[this] inside a class and providing a class parameter without val/var is same.
Well, it's not the same because with class ABC(x: Int) you have a constructor accepting Int.

Access a constant from the companion class inside a method defined in a trait

I have created a trait called Animal and two classes, Dog and Cat. Both Dog and Cat have companion classes that store the number of lives they have. My Cat object has 9 lives and my Dog object has 1 life. I want to add a function to the Animal trait called isAlive and implement there. The isAlive function needs access to the number of live the Animal has. How would I get access to the lives value in the companion classes?
Should I just move the lives value into the Class and remove the companion classes?
Here's my code.
The trait
package Animal
trait Animal {
def speak: String
def getDeaths: Int
def isAlive: Boolean = {
getDeaths < 1 // I want to replace 1 with the number of lives from the Dog or Cat
}
}
The Cat Class and Companion Class
package Animal
class Cat(a: Int) extends Animal {
private var age: Int = a
private var deaths: Int = 0
def this() = this(0)
override def speak: String = {
if (this.isAlive) {
"Meow"
}
else {
"..."
}
}
// I want to do this in the trait
// override def isAlive: Boolean = this.deaths <= Cat.lives
def setAge(age: Int): Unit = this.age = age
def getAge: Int = this.age
def getDeaths: Int = this.deaths
def die(): Unit = this.deaths += 1
}
object Cat {
val lives: Int = 9
}
I'd include lives as an abstract method in Animal trait, similar to getDeaths (btw, Scala doesn't follow Java's naming conventions for getters and setters).
If you're familiar with Java, companion object in scala is similar to Java's static, meaning that type resolution of objects happens in compile time and it's not possible to use polymorphism the same way as you do with methods and fields of the class.
Here is the code:
trait Animal {
def speak: String
def getDeaths: Int
def lives: Int
def isAlive: Boolean = {
getDeaths < lives
}
}
class Cat(a: Int) extends Animal {
override val lives: Int = 9
private var age: Int = a
private var deaths: Int = 0
def this() = this(0)
/* ... */
}
Alternatively, you can defined lives constant in companion object and reference it in concrete class when overriding lives method:
class Cat(a: Int) extends Animal {
override val lives: Int = Cat.lives
private var age: Int = a
private var deaths: Int = 0
def this() = this(0)
/* ... */
}
object Cat {
val lives = 9
}
To access lives within a trait it either has to be a part of the trait, as #Alvean has pointed out, or you have to make it a requirement that classes extending the trait need to have it.
trait Animal { self: {val lives: Int} =>
def isAlive: Boolean = getDeaths < lives
. . .
}
class Cat(a: Int) extends Animal {
val lives = Cat.lives //required to be an Animal
. . .
}

Scala: create instance from generic type with private constructor

I have a class with a generic type parameter and I would like to create an instance of this type using reflection. Moreover, the type has a private constructor.
Here is a code sample of the problem:
class X private (x: Int) {
}
class Y private (y: Int) {
}
abstract class Foo[T](z : Int) {
var bar : T = createInstance[T](z)
def createInstance[T](z: Int) : M = {
???
}
}
This would allow me to instantiate Foo and access bar:
class xFoo extends Foo[X]{
}
class yFoo extends Foo[Y]{
}
var xfoo = new xFoo(5)
println(xfoo.bar.x)
var yfoo = new yFoo(6)
println(yfoo.bar.y)
This should print out '5' and '6'.
I have tried using implicit in the following way.
def createInstance[T](z: Int)(implicit tag: TypeTag[T]) : T = {
val clazz = tag.tpe.getClass
val ctor = class.getDeclaredConstructor(classOf[Int])
ctor.setAccessible(true)
return ctor.newInstance(z).asInstanceOf[T]
}
However, then I get the error:
No TypeTag available for T
in line
var bar : T = createInstance[T](z)
Any suggestions? Thanks for your help!
Assuming that the super class does expose some method/value you're looking for like:
class X private(val x: Int) {}
You can extend it like so:
import scala.reflect._
class Foo[T](z : Int)(implicit ct: ClassTag[T]) {
var bar : T = createInstance[T](z)
def createInstance[T](z: Int) : T = {
val ctor = ct.runtimeClass.getDeclaredConstructor(classOf[Int])
ctor.setAccessible(true)
ctor.newInstance(Int.box(4)).asInstanceOf[T]
}
}
This enables you to call:
class XFoo(n: Int) extends Foo[X](n)
println((new XFoo(5)).bar.x)

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

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.

Scala Stackable Trait and Self Type Incompatible Type

I have a trait called Mutatable that spits out a modified copy of an implementing class. I also have a trait I'd like to stack on top of it called CostedMutatable that keeps track of the cost of doing so. The method applyMutation returns an Option, as later I'd like to return None in cases where a particular mutation doesn't apply.
A simple version that just works on Ints (and "mutates" them by adding in new numbers) is shown below:
trait Mutatable[M] {
def applyMutation(mut : M) : Option[this.type]
}
trait CostedMutatable[M] extends Mutatable[M]{
var cost : Int = _
def getCostFor(mut : M): Int
abstract override def applyMutation(mut : M) : Option[this.type] = {
cost += getCostFor(mut)
applyMutation(mut)
}
}
object Example extends App {
case class Mutation(x: Int)
class Test(s: Int) extends Mutatable[Mutation] {
val start = s
override def applyMutation(mut: Mutation): Option[Test]
= Some(new Test(s+mut.x))
}
class CostTest(s: Int) extends Test(s) with CostedMutatable[Mutation] {
override def getCostFor(mut: Mutation): Int = 2
}
val testCost = new CostTest(5).cost
}
The problem is, this won't compile. I get the following error on compilation:
Error:(23, 18) overriding method applyMutation in trait Mutatable of type (mut: Example.Mutation)Option[Test.this.type];
method applyMutation has incompatible type
override def applyMutation(mut: Mutation): Option[Test] = Some(new Test(s+mut.x))
^
Aside from the compiler error, one other question comes to mind: am I even approaching this the right way? Should I be using F-bounded types instead? (I'll need each new implementing class to return a new copy of the concrete implementing class from applyMutation.)
Thanks in advance.
this.type is a type the only instances of which are this and Nothing. When a method returns this.type, the only allowed return value is this. In class Test applyMutation doesn't return this, but rather a completely new Test, which isn't an instance of this.type. This is why the code does not type-check.
I think what you are really trying to do is declare that applyMutation returns a value of the same class as this. Doing this does indeed require F-Bounded polymorphism. Here is a rewritten version of your code:
trait CostedMutatable[+A <: CostedMutatable[A, M], M] extends Mutatable[A, M] {
var cost : Int = _
def getCostFor(mut : M): Int
abstract override def applyMutation(mut: M): Option[A] = {
cost += getCostFor(mut)
super.applyMutation(mut)
}
}
object Example extends App {
case class Mutation(x: Int)
class Test(s: Int) extends Mutatable[Test, Mutation] {
val start = s
override def applyMutation(mut: Mutation): Option[Test]
= Some(new Test(s+mut.x))
}
class CostTest(s: Int) extends Test(s) with CostedMutatable[CostTest, Mutation] {
override def getCostFor(mut: Mutation): Int = 2
}
val testCost = new CostTest(5).cost
}