Mastering Scala Basics: Expressions, Types, Values & Methods

Expressions are parts of a program that evaluate to a value. For example:

val a = 3 + 5
// a evaluates to 8

A value is an information stored in computer’s memory and exists at run time. In the above example, values 3 and 5 are combined to create another value 8.

Types restrict us to write programs that give a consistent interpretation to values. Type annotations are patterned as follows:

value: Type

From the above example, the type of a is Int. But, if we change the expected type to String, we get an error:

val a: Int = 3 + 5

// change the type to String
val a: String = 3 + 5 
// error: type mismatch;

Types exist at compile time, so the above example will show compilation issues, thereby restricting us to write correct programs. Two rules for type inference:

  1. Never annotate the type of a private field or a local variable, as their type is immediately evident from their value.
  2. All public methods should have explicit type annotations. It helps in making sure that when changing to a different type, we get an error if we are potentially breaking the client code. In addition, it helps in improving compile times.

Object is a grouping of data and operations on that data. The data are known as fields and the operations are known as method. All values in Scala are objects.

Methods

We interact with objects via methods. For example:

"Scala".charAt(3)
// val res0: Char = l

"Scala".length // takes no parameters
// val res1: Int = 5

Since a method call is an expression, thus evaluates to an object (remember - all values in Scala are objects). This means we can chain method calls together.

"Scala".toUpperCase.charAt(3)
// val res2: Char = L

Syntax of a simple method looks like:

// method declaration syntax
def name(param:type, ...): resultType = 
    bodyExpression

// example
def add(a: Int, b: Int): Int = a + b

// invoking a method
val total = add (1, 2)
// evaluates to 3

For methods that take no parameters:

  • If the method performs side effects, such as println , declare the method with empty parentheses.
  • If the method does not perform side effects, like getting the size of a collection then leave the parentheses off.
def sayHello() = println("Hello")

sayHello()
// Hello

Literal expression represents a fixed value that stands “for itself”. For example:

10
// val res3: Int = 10

You may have already seen these in another programming languages; some of the object literals in Scala:

// Number
10
// val res3: Int = 10

10.0
// val res4: Double = 10.0

// Boolean
true
// val res5: Boolean = true

false
// val res7: Boolean = false

// Character
'c'
// val res8: Char = c

// String
"hello scala"
// val res9: String = hello scala

// null has its own type - Null
null
// val res10: Null = null

// Unit, written ( ), is the Scala equivalent of Java’s void.
:type ()
// Unit

println("something")
// something

:type println("something")
// Unit

Those are the Scala built-in types, now let’s use an object literal to create objects.

To write an object literal, we use a declaration, which does not evaluate to a value rather associates a name to a value.

// binds name (Person) to a value (empty object)
object Person {}

Person
// val res12: Person.type = Person$@6ecf239d

// object declaration syntax
object name {
    declarationExpression
}

Let’s add a few methods to Person:

object Person {
    def name: String = "Jill Doe"
    def fullName(first: String, last: String) = 
        first + " " + last    
}

Person.fullName("John", "Doe")
// val res13: String = John Doe

An object can contain another object called fields (data). We add fields using val or var keyword:

object Person {
    val name: String = "Jill"
    def greetings(otherName: String) = 
        "greetings " + otherName + ", from " + name
}

Person.greetings("John")
// val res14: String = greetings John, from Jill

// field declaration syntax
val name:type = valueExpression
var name:type = valueExpression

val defines an immutable variable just like final in Java. Always create a variable with val, unless there's a reason you need to mutate variable.

var defines a mutable variable and should only be used when a variable’s contents will change over time.

Methods vs fields

Field gives name to a value; Method gives name to a computation that produces a value. In addition, Objects and classes in Scala aren’t loaded until they are referenced by the code (lazy loading).

object Test {
    val someField = {
        println("Printing field")
        100
    }

    def someMethod = {
        println("Printing method")
        100
    }
}

Test
// Printing field
// val res15: Test.type = Test$@2f931d5d

What happened in there?

When objects are loaded in Scala, it calculates the values of the fields. The body expression of the field is run only once after the final value is stored in the object and the expression is never evaluated again. For example: println is not in the output:

Test.someField
// val res16: Int = 100

On the other hand, the body of the method is evaluated every time we call it.

Test.someMethod
// Printing method
// val res17: Int = 100

Test.someMethod
// Printing method
// val res18: Int = 100

References used are scala doc and essential scala