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.
Related
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.
class Person(){
val name : String
def this(n : String) {
this()
this.name = n
}
}
compile time error : reassignment to val
i am a newbie to scala and so far i learned how to use primary constructor and case classes for initialization of data members. I am just wandering, if there is a way to initialize val data member inside this. Initialization of var data member works fine below :-
class Person(){
var name : String = _
def this(n : String) {
this()
this.name = n
}
}
You just can't assign to a val after initialization. In Scala the body of the class IS the constructor, you can see examples here.
In general, you just define all variables in the primary constructor itself as "class parameters": class Person(val name: String) if you need to receive the name for initialization or class Person() { val name = 'Joe' } if it is fixed.
This can be quite surprising coming from Java, as you are used to have constructors that produce the values and build the object directly. For such a case, the best solution is to use apply methods on a companion object:
class Person(val name: String)
object Person() {
def apply(db: SomeDBConnectionWrapper, id: Int) = new Person(db.fetchName(id))
}
That allows you to call Person(db, 3) to get a new person with custom initialization, but the constructor itself still receives all it needs to construct a new instance where all values are only assigned once.
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.
I am exploring Scala by rewriting some of my Java code with it. In one of the Java method, I need to pass a class type as a parameter:
public void setType(Class<T> type)
In Java, I could do it by:
someobj.setType( MyClass.class )
But in Scala, I can't seem to call "MyClass.class". I am wondering how I can pass the parameter in Scala?
You're after classOf[MyClass].
scala> case class MyClass()
defined class MyClass
scala> def setType[T](t:Class[T]) = println(t)
setType: [T](t: Class[T])Unit
scala> setType(classOf[MyClass])
class $line23.$read$$iw$$iw$MyClass
Philippe correctly points out that the OP needs to call a Java method from Scala. In that case, more info about the java class is needed to determine intent, but something like this:
Java:
public class JavaClass<T> {
public void setType(Class<T> type) {
System.out.println(type);
}
}
Scala:
class MyClass()
object classtest {
val someobj = new JavaClass[MyClass] //> someobj : JavaClass[MyClass] = JavaClass#6d4c1103
someobj.setType(classOf[MyClass]) //> class MyClass
}
There's one more way to do so if you just need to pass class type and use it to model data or /create new instances.
def doSomeThing[T](id: UUID, time: Date): List[T] = {
// do anything with T, it's a reference to class definition not an instance
List(T(id, time), T(id, new Date(time.getTime + 900 * 1000))
}
case class SomeClassA(id: UUID, time: Date)
case class SomeClassB(id: UUID, time: Date)
class NonCaseClass(p1: UUID, p2: Date)
doSomeThing[SomeClassA]()
doSomeThing[SomeClassB]()
doSomeThing[NonCaseClass]()
I have made this code little complex, here's the wrapper only example:
def doSomeThing[T]() = {
// do anything with T, it's a reference to class definition not an instance
}
case class SomeClassA(id: UUID, time: Date)
doSomeThing[SomeClassA]()
My question is about scala inheritance details. I have the following code.
package scalasandbox
object Main {
def main(args: Array[String]): Unit = {
val creature: Creature = new Human("First")
creature.rename("Second")
creature.introduce
}
}
class Creature(var name: String) {
def introduce = println("I'm creature: " + name)
def rename(newName: String) = {
println("Creature was renamed to: " + newName)
name = newName
}
}
class Human(name: String) extends Creature(name) {
override def introduce = println("I'm Human: " + name)
}
which produces the following output
Creature was renamed to: Second
I'm human: First
I expect it to be "I'm human: Second" because rename method should change the field value. I have opened Human class with decompiler:
package scalasandbox;
import scala.Predef.;
import scala.ScalaObject;
import scala.collection.mutable.StringBuilder;
import scala.reflect.ScalaSignature;
#ScalaSignature(bytes="\006\001\0212A!\001\002\001\013\t)\001*^7b]*\t1!\001\007tG\006d\027m]1oI\n|\007p\001\001\024\007\0011!\002\005\002\b\0215\t!!\003\002\n\005\tA1I]3biV\024X\r\005\002\f\0355\tABC\001\016\003\025\0318-\0317b\023\tyABA\006TG\006d\027m\0242kK\016$\b\002C\t\001\005\003\005\013\021\002\n\002\t9\fW.\032\t\003'Yq!a\003\013\n\005Ua\021A\002)sK\022,g-\003\002\0301\t11\013\036:j]\036T!!\006\007\t\013i\001A\021A\016\002\rqJg.\033;?)\taR\004\005\002\b\001!)\021#\007a\001%!)q\004\001C!A\005I\021N\034;s_\022,8-Z\013\002CA\0211BI\005\003G1\021A!\0268ji\002")
public class Human extends Creature
implements ScalaObject
{
private final String name;
public void introduce()
{
Predef..MODULE$.println(new StringBuilder().append("I'm Human: ").append(this.name).toString());
}
public Human(String name)
{
super(name);
}
}
and see "private final String name;" there. I think it hides Creature name field. And
Predef..MODULE$.println(new StringBuilder().append("I'm Human: ").append(this.name).toString());
this stuff looks also suspicious because of "this.name" instead of method call "this.name()". Could anyone explain where is my mistake and what is the correct way of implementing those two classes?
The name variable that you use in the Human class resolves to the constructor parameter of Human, and Scala will automatically create private vals for constructor parameters that you use outside the constructor. This is unfortunate in your case. You can prevent this e.g. by naming your parameter in Human differently, e.g. nm:
class Human(nm: String) extends Creature(nm)
try by changing this line:
class Human(foo: String) extends Creature(foo) {
so you don't hide name.
If Creature is only intended for subclassing, I'd advise that you make both the class and the name parameter abstract, as per my answer here:
Idiomatic Scala way to deal with base vs derived class field names?
One advantage to such a technique is that it then becomes far easier to use case classes for the specific, concrete, sub-classes