Classes and Objects - rohgar/scala-principles-1 GitHub Wiki
Here we will learn how functions can create and encapsulate data structures.
Classes
A class in scala can be defined with its constructor as below:
class Foo(x: Int, y: Int) {
def numer = x
def denom = y
}
This definition has 2 entities:
- A "type" named Foo
- A Constructor to create elements of this type.
Scala keeps types and values in different namespaces, so there is no conflict between the definitions of Foo.
Implicit class variables
In the above examples, instead of taking constructor params and assigning them to class variables/constants, we can directly generate implicit class variables/constants in the constructor:
class Foo2(var numer: Int, val denom: Int) {
}
Here numer
is a variable and denom
is a constant. No getters/setters needed. These implicit variables can also have access specifiers eg. private
.
So here, you cannot do:
println(Foo.x) // since its just a parameter and not a class variables
but we can do this:
println(Foo2.numer)
Note: As seen above, in case of classes, using a keyword like var
or val
before the param name makes it a class variable. Leaving out the keyword makes it a parameter. However, in case of functions, parameters are assumed to be val
.Eg.
def foo(x: Int) = {}
is the same as
def foo(val x: Int) = {}
Objects
Objects are elements of a class type, created by using the new
keyword.
val foo = new Foo(1,2)
Methods
Functions can be packaged in the class:
class Foo(x: Int, y: Int) {
def numer = x
def denom = y
def multiplyBy(that: Foo) {
new Foo( numer * that.numer, denom * that.denom )
}
}
// call
val foo1 = new Foo(1,2)
val foo2 = new Foo(5,6)
foo1.multiply(foo2)
Some pointers
- String Representation: Overwrite the
toString()
method of a class to provide a custom string representation of a class, just like in JAVA. - Access Specifiers: Variables and function definitions in a class that are only for use inside the class can be marked with the private access specifier like in JAVA.
- this: The
this
keyword can be used inside a class to refer to current object.
require and assert
The require
keyword be used to define requirements of a particular class. It takes in a condition and an optional message.
Example:
class Foo(x: Int) {
require( x! = 0, "Integer must be non-zero")
def numer = x
def divideBy(that: Foo) {
new Foo( this.numer / that.numer)
}
}
So if we call:
val foo1 = new Foo(4)
val foo2 = new Foo(0)
foo1.divideBy(foo2) // Fails with "IllegalArgumentException: requirement failed: Integer must be non-zero"
Similarly assert
also takes in a condition and an optional message.
val x = sqrt(y)
assert(x >= 0)
// Fails with AssertionError instead of IllegalArgumentException
The difference between require
and assert
is the "intent" of use.
- require is used to enforce a precondition on the caller of a function
- assert is used to check the code of a function
Constructor
Classes are defined with an implicit constructor which is the primary constructor. Additional constructors can be defined by using the this
keyword.
class Foo(x: Int, y: Int) {
def numer = x
def denom = y
// additional constructor which uses the primary constructor
def this(x: Int) = {
this(x, 1)
}
def multiplyBy(that: Foo) {
new Foo( numer * that.numer, denom * that.denom )
}
}