05. Classes - RobertMakyla/scalaWiki GitHub Wiki
Class
In one file there might be multiple classes, and all of them are public by default, so no need to write 'public' Methods are functions or procedures in a class. Methods are public BY DEFAULT
class Counter {
private var value = 0 // You MUST initialize the field
def increment() { value += 1 } // procedure (Methods)
def current = value // function (Method)
}
using Class
val c = new Counter() // or val c = new Counter
c.increment() // or c increment() or c increment
c.current // or c current
If I declare function without parentheses "def current = ..." then I am forced to use myCounter.current without parentheses.
If I declare function with parentheses "def increment() ..." but without arguments then I can call it both ways.
Methods that changes state, should be declared with () even if it doesn't take parameters.
Getters and Setters added by Scala: getter: myCass.myField setter myCass.myField_=(newValue)
class Person {
var age = 0 // public field by default
} // for a private field, getter/setter are also private
getters and setters (interview)
When compiling a class, Scala creates getters and setters (Java methods):
For public variable :
public int age // person.age - allowed ; person.age() - not allowed
public void age_$eq(int) // person.age_=(10) or person.age = 10
For public value :
public int age // just getter
For private variable :
private int age
private void age_$eq(int)
For object-private variable/value :
// no getter or setter
Overriding Getters and setters - it's possible to make private fields visible outside class (interview)
class Person {
private var privateAge = 0 // private getter/setter
def age = privateAge // overriding private getter
def age_=(age: Int) { // overriding private setter
if (age> privateAge) privateAge = age;
}
}
Instead of 'age_=()' I could define more natural 'age()'. It's just another setter, which I can add.
However only 'age_=()' let me use 'person.age = 100' . The other let 'person.age(100)' or 'person age 100'
Creating custom functions instead of getters and setters (Encapsulation)
class Counter {
private var value = 0
def current = value
def increment() { value += 1 }
}
To summarize (interview)
- var foo: Scala creates a **getter ** and a setter
- val foo: Scala creates a getter
- You can define custom methods foo and/or foo_=() which override the default getters/setters
Note: In Scala, you cannot have a write-only property (property with a setter and no getter).
Note: In Scala, when a field is private, the getter/setter (for variable) or just getter (for value) are also private. But I can override it to be public (as above)
Accessing private fields (interview)
In Scala as in Java, method can access private fields from other objects of the same class !!
class Counter {
private var someVar = 0 // same as private[Counter]
// meaks that methods from Counter will have access to getter and setter
def increment() { someVar += 1 }
def isLess(other : Counter) = someVar < other.someVar
} // it can access other.someVar as private field of other object
Object-Private fields (interview)
Note: If we wrote private[this] var value = 0 then accessing this private field from different object wouldn't be possible, even if it's the same class.
class Counter {
private[this] var someVar = 0
def increment() { someVar += 1 }
def current = someVar // necessary cause inLess() I cannot access other.someVar
def isLess(other : Counter) = someVar < other.current
}
Note: For private var, scala generates private getter and setter
Note: For object-private var, scala does not generate getters or setters
Note: private[SomeClass] - means that methods from SomeClass will have access to this field
JavaBeans
Making scala generate JavaBean getters/setters (for Tools such as Spring/EJB)
import scala.reflect.BeanProperty
class Person {
@BeanProperty var name: String = _ // or = null
}
This generates:
- name: String
- name_=(newValue: String): Unit
- getName(): String
- setName(newValue: String): Unit
Auxiliary (pomocnicze) Constructors (interview)
NOT REALLY SCALA WAY - too much of code - Primary Constructors are better, more concise
Auxiliary constructors are always called 'this'
Each auxiliary constructor MUST start with a call to a previous constructor (previous can be auxiliary or primary)
class Person {
private var name = ""
private var age = 0
def this(name: String) { // First auxiliary constructor
this() // MUST Call primary constructor - otherwise compilation error
this.name = name // cause it's a first auxiliary
}
def this(name: String, age: Int) { // Another auxiliary constructor
this(name) // MUST Call any other constructor
this.age = age // (primary or auxiliary)
}
}
new Person // Primary constructor
new Person("Fred") // First auxiliary constructor
new Person("Fred", 42) // Second auxiliary constructor
Primary Constructor (SCALA WAY) (interview)
If there are parameters after the class name, then the class has a primary constructor with this args
If there are no parameters after the class name, then the class has a primary constructor with no parameters.
the primary constructor simply executes all statements in the body of the class
class Person(val name: String, val age: Int) {
println("Executed by primary constructor")
def description = name + " is " + age + " years old"
}
Primary Constructor arguments (val name: String, var age: Int) are declaring fields and also methods:
-
name:String // no name_=(newName:String):Unit cause name is a value
-
age:Int
-
age_=(newAge:Int):Unit
class Hi{ println("Hi was created")} ; val h = new Hi // "Hi was created"
class Person(var age:Int = 29){ print("Person was created") age += 1 } val p = new Person // "Person was created" p.age // 30
Default values in primary constructor
class Person(val name: String = "Robert", val age: Int = 29)
val p = new Person // Robert 29
val p = new Person("Robert",99) // Robert 99
val p = new Person(name = "Marko") // Marko 29
val p = new Person("Marko") // Marko 29
val p = new Person(age = 99) // Robert 99
val p = new Person(99) // Error: Invalid first default argument
If we want to skip the name of arg on right side, all other args on left must be provided (with name or not)
Object-Private fields in primary constructor (interview)
class Person( name: String ) // this is OBJECT PRIVATE
// declares fields: private[this] val name: String
// if not used in this class, it's inaccessible from outside
// if used it in this class, it's read-only cause it's a val
class Person(private[this] val name: String ) {} // the same
class Person(private[this] var name: String ) {} // also possible
// it's read-write from inside of class
to sum-up (interview)
- private val/var name: String
this gives PRIVATE field and PRIVATE SCALA getters (and setters for variable), it's exactly like private[MyClass]
- val/var name: String
this gives PRIVATE field but PUBLIC SCALA getters (and setters for variable) (interview)
- @BeanProperty val/var name: String
this gives PRIVATE field but PUBLIC SCALA getters and JavaBeans getters (and setters for variable)
Private primary constructor (interview)
class Person private(val id: Int) { ... }
Useful to mark that only companion object (the apply() method) can create an instance (interview)
That's because Companion Object can still call private constructor
Or to secure using constructor by DI framework (e.g. Google GUICE)
Requirements of class - throws IllegalArgumentException (interview)
class Person(age:Int){
require(age>=0 , "Age must be positive")
}
val p = new Person(-1) // --> IllegalArgumentException
It's different that assert(Boolean) which throws AssertionError: assertion failed
Both functions: require(boolean, String) and assert(boolean) are predefined
Nesting
In scala I can nest classes in other classes, or functions in other functions.
In scala, inner class does not belong completely to outer class (unlike in Java) :
In scala: val inner = new myOuterClass.myInnerClass // so just adding outer class as prefix in name
In java: Object inner = myOuterClassObject.new myInnerClass() // need object of outer class to create/access inner