Please help me understand overriding of val in scala - scala

I asked a question earlier: here and although I accepted the answer I'm still very far from actually understanding, so I dug a bit deeper and I'm writing a further question.
The behaviour of overriding val in scala surprises me. For example, given this code:
class A {
val name = "AAAAA"
}
class B extends A {
override val name = "BBBBB"
}
if I say:
object Atest extends App {
val b = new B
println(b.name)
val a = b.asInstanceOf[A]
println(a.name)
}
I expect
BBBBB
AAAAA
but I get
BBBBB
BBBBB
I'm just trying to see the AAAAA value that I think A should be storing somewhere. So I try:
class A {
val name = "AAAAA"
def showSuper {
println(name)
}
}
and:
val b = new B
val a = b.asInstanceOf[A]
b.showSuper
a.showSuper
but I still get:
BBBBB
BBBBB
So I try do have a look at what scala is actually generating from my classes:
scalac -Xprint:all A.scala
gives me
class A extends Object {
private[this] val name: String = _;
<stable> <accessor> def name(): String = A.this.name;
def <init>(): p3.A = {
A.super.<init>();
A.this.name = "AAAAA";
()
}
};
class B extends p3.A {
private[this] val name: String = _;
override <stable> <accessor> def name(): String = B.this.name;
def <init>(): p3.B = {
B.super.<init>();
B.this.name = "BBBBB";
()
}
}
The call to B.super happens before B.this.name even gets set and A clearly sets its name to AAAAA.
What is going on? Why, when I override a val like this, can I not see A's value (or is it getting set to B's value?) What is the mechanism by which this happens? How can I see this mechanism - is there a piece of scala source code that shows me why this happens?
Many thanks
EDIT:
Meant to add that if I use javap to look at the bytecode, it clearly shows that A and B each have their own copy of the name variable:
$ javap -private A
Compiled from "A.scala"
public class p3.A extends java.lang.Object{
private final java.lang.String name;
public java.lang.String name();
public p3.A();
}
$ javap -private B
Compiled from "A.scala"
public class p3.B extends p3.A{
private final java.lang.String name;
public java.lang.String name();
public p3.B();
}
So it's not like A and B have to be sharing the same variable - they each have the potential for using their own copy.

That is not Scala specific. It is OOP question. The second class override the method and hides it.
Overriding and Hiding Methods

Just some extra notes. It transpires that if you decompile the scala classes, you find that scala changes references to vals to references to the methods that get the vals. For example where my class A above has:
def showSuper {
println(name)
}
the decompiled bytecode shows
public void showSuper()
{
Predef..MODULE$.println(name());
}
(thanks to jd-gui)
So this makes it clear that scala references to vals are equivalent in bytecode to java's polymorphic method calls rather than java's variables which are type dependent.

Related

class can't have main() in scala?

I'm a beginner of Scala.
In Calulator.scala file
class Calulator {
var brand: String ="HP"
def add(m:Int, n:Int):Int = m+n
}
In CalculatorTest.scala file
object CalulatorTest {
def main(args:Array[String]) {
val cal = new Calulator
println(cal.add(1,2))
}
}
Compile two scala files and run CalculatorTest. This works.
My question is can I make them as one scala file like Java?
In Calulator.scala file
class Calulator {
var brand: String ="HP"
def add(m:Int, n:Int):Int = m+n
def main(args:Array[String]) {
val cal = new Calulator
println(cal.add(1,2))
}
}
This doesn't work !!!
I googled it and looks like main() should be in object.
Is there a way to put them in one file to run main()?
To put them in one file use the concept of the 'Companion Object'.
The class and companion object must be in the same file and share the same name.
class Calculator {
var brand: String = "HP"
def add(m: Int, n: Int): Int = m + n
}
object Calculator {
def main(args:Array[String]) {
val cal = new Calculator
println(cal.add(1,2))
}
}
Further reading: http://docs.scala-lang.org/tutorials/tour/singleton-objects.html
The simple answer is No
a deeper answer is that the scala compiler refers to an object as static and class it refers as regular.
when you want to run Java program your main must be declared as static otherwise the JVM will not recognize it as your program entry point.
regards the question about is it possible to union both of them ,the answer is not because thats how the scala compiler works.
The compiler would create MyClass$.class for scala object and MyClass.class for scala class thats why you should never ever call your class something like :
class MyClass$ {
}
because it will override the companion object for MyClass.

What is val at class parameter in Scala?

I see something like below sometimes.
class Test(val str: String){
}
I wrote some sample code with val though, I don't see any difference between common declaration and the way with val.
What is the difference between them?
and When should it be used?
If you add val, your variable will be visible from outside of class.
// 'name' is a val
class Person(val name: String)
val p = new Person("Alvin Alexander")
p.name // String = Alvin Alexander
p.name = "Fred Flintstone" // error: reassignment to val
// 'name' is neither var or val
class Person(name: String)
val p = new Person("Alvin Alexander")
p.name // error: value name is not a member of Person
The code was taken from http://alvinalexander.com/scala/scala-class-examples-constructors-case-classes-parameters
More info scala class constructor parameters
By adding to #EntryLevelDev's answer, you can use javap to see what really happened.
1.scala
class Test(val str: String){
}
step1. scalac 1.scala
step2. javap Test
Compiled from "1.scala"
public class Test {
public java.lang.String str();
public Test(java.lang.String);
}
2.scala :
class Test2(str: String){
}
step1. scalac 2.scala
step2. javap Test2
Compiled from "1.scala"
public class Test1 {
public Test1(java.lang.String);
}
So when you add val, scala generates a method by the argument's name, and is made public so is visible from outside.

How to circumvent invariance? E.g. passing Array[T] to func(Array[U]) where T<:U

I'm practicing scala using an existing java library. It's quite common to pass Array[T] to func(Array[U]) where T<:U. For example:
Java:
public class Quick { ...
public static void sort(Comparable[] a) { ... }
}
public class Edge implements Comparable<Edge> { ... }
public class EdgeWeightedGraph { ...
public Iterable<Edge> edges() { ... }
}
Scala:
class Kruskal(private val G: EdgeWeightedGraph) {
init()
private def init() = {
val es = G.edges().asScala.toArray
/* **Error** Type mismatch,
* expected: Array[Comparable[_]],
* actual: Array[Edge]
*/
Quick.sort(es)
...
}
}
I believe it's because the fact that Array is invariant. Here's my attempt to circumvent this, but it looks ugly and inefficient:
val es = G.edges().asScala.map(_.asInstanceOf[Comparable[_]]).toArray)
Quick.sort(es)
How do I do it in a better way?
Arrays are invariant because they are mutable. If they weren't invariant you could do something like
class Fruit
class Apple extends Fruit
class Orange extends Fruit
val apples:Array[Apple] = Array(new Apple())
val fruits:Array[Fruit] = apples
fruits.update(0,new Orange)
val apple:Apple = apples(0) //<= epic fail I now have an orange as an apple ?
The only way I can think of is to copy the collection to an equivalent immutable collection (subtype of collection.immutable.Seq)
class Fruit
class Apple extends Fruit
class Orange extends Fruit
val apples:Array[Apple] = Array(new Apple())
val fruits:collection.immutable.Seq[Fruit]=apples.toList // or apples.toIndexedSeq
then get an immutable collection and you can get variance
in your specific example you could change
val es = G.edges().asScala.toArray
to
val es = G.edges().asScala.toIndexedSeq
but then you will have to make the QuickSort signature accept an IndexedSeq I guess. It is hard to tell the consequences without more code ...

Scala - construction order and early definition syntax

I'm trying to learn Scala and thought I would begin by reading "Scala for the Impatient". There he cites the problem of construction order by using the following classes:
class Animal {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Animal {
override val range: Int = 2
}
and then he explained why the env ends up being an empty Array[Int] and proceeds to explain ways to prevent that, including the early definition syntax.
But... can't I prevent that just by doing this:
class Animal(val range: Int = 10) {
val env: Array[Int] = new Array[Int](range)
/* do animal stuff */
}
class Ant(override val range: Int = 2) extends Animal(range) {
/* do ant stuff */
}
??? Why is the early definition syntax really necessary?
I think a better way to look at the need for early instantiation comes from mixing in traits. With traits, you won't have a constructor that you can tweak to get around this kind of issue. Consider this very trivial and completely unrealistic example:
trait Foo{
val bar:String
val barLength = bar.length()
}
object MyFoo extends Foo{
val bar = "test"
}
As it stands right now, this code will throw a NullPointerException when MyFoo is created because bar will not yet be defined when bar.length() is invoked. But if you used early initialization, and redefined MyFoo as:
object MyFoo extends {val bar = "test"} with Foo{
}
then everything works just fine.

Public variables in Scala?

Are there public instance variables anymore in Scala? I'm reading Programming in Scala, which covers Scala 2.8. If I'm understanding it correctly, it claims that vars in 2.8 are by default public.
I'm trying to write code for 2.9.1.final now, and instance variables are now by default private? But there's no public keyword that I'm aware of. (Interestingly enough, it appears it used to exist sometime in the 2.x series, but it mysteriously disappeared somewhere along the line.)
Am I missing something obvious?
Also, by extension, is there an easy way to declare a variable passed to a class constructor to be public (since it appears that those also have default private visibility now too)?
Example:
class Instance(label: String, attributes: Array[Int]){
val f = 0
}
Eclipse claims that label, attributes, and f are all private. Scala 2.9.1.final is being used as the library.
In scala, if you omit the modifer, then instance fields are public by default:
scala> class Foo { var foo = 1 }
defined class Foo
scala> class Bar { def bar() = { val f = new Foo; f.foo = 5; }}
defined class Bar
No worries there. However, when you use a variable in a constructor, the variable is not necessarily turned into a field:
scala> class Foo(foo: Int)
defined class Foo
scala> class Bar { def bar() = { val f = new Foo(5); println(f.foo) }}
<console>:8: error: value foo is not a member of Foo
class Bar { def bar() = { val f = new Foo(5); println(f.foo) }}
^
so you can declare it as a val or var to have it available:
scala> class Foo(val foo: Int)
defined class Foo
scala> class Bar { def bar() = { val f = new Foo(5); println(f.foo) }}
defined class Bar
Note that all fields are actually private, but scala exposes accessor methods (foo() and foo_=(t: Int)) to enable you to access the fields), which is why scala-ide says that the fields are private (assuming you mean when you hover over the variable).