Scala

File size
15.5KB
Lines of code
356

Scala

Hybrid functional and object-oriented programming language that compiles to Java bytecode.

REPL

Scala features a REPL analogous to a commandline interpreter. Any Scala expression received will be evaluated and printed to the stdout.

# ----- Scala REPL -----

$ scala # initialises a Scala REPL as below
scala>

scala> 2 + 2 # each typed expression is automatically saved as a new numbered value
res0: Int = 4

scala> res0 + 2 # previously declared values can be called
res1: Int = 6

scala> :type (true, 2.0) # checking type of a literal without evaluating an expression
(Boolean, Double)

scala> :save /sites/repl-test.scala # saves a Scala REPL session

scala> :load /sites/repl-test.scala # load a Scala file into the REPL to automatically evaluate it
Loading /sites/repl-test.scala...
res2: Int = 4
res3: Int = 6

scala> :h? # browse REPL history to see past expressions entered
1 2 + 2
2 res0 + 2
3 :save /sites/repl-test.scala
4 :load /sites/repl-test.scala
5 :h?

Comments

// ----- COMMENT -----

// this is a single-line comment

/* 
this is a 
multi-line
comment
*/

Printing

// ----- PRINT -----
    // print() => print text to the stdout without a newline
    // println() => print text to the stdout with a newline

print("there's no newline and we must explicitly specify it\n")
println("this includes a newline automatically")

Imports

// ----- IMPORT -----
    // a Scala file can contain multiple classes and objects
    // import => specifies packages, sub packages and classes to bring into the local scope of the current Scala file
    // {} => group multiple import items together
    // => => rename an import item within the local scope for easier reference
        // _ => can be combined with above to exclude specific import items from being imported

import scala.collection.immutable.List
import scala.collection.immutable._ // this is a sub package
import scala.collection.immutable.{List, Map} // import multiple classes at once
import scala.collection.immutable.{List => ImmutableList} // rename the import from List to ImmutableList
import scala.collection.immutable.{Map => _, Set => _, _} // import all classes except the specified Map and Set

Input and Output

// ----- INPUT AND OUTPUT -----
    // scala.io.Source => package containing read and write methods, has to be imported
        // .fromFile() => opens file at specified file path
        // .getLines() => retrieves all the lines within a file and stores them within an iterable structure that can be iterated over with a loop
    // PrintWriter() => initialses a new PrintWriter write object on the file at the specified file path
        // util.Properties => package containing further formatting options for writing to the specified file
        // .write() => writes the designated text as a string to the file
        // .close() => closes the PrintWriter object

// --- INPUT ---
    // performs read actions

import scala.io.Source // required import
for(line <- Source.fromFile("myfile.txt").getLines())
    println(line)

// --- OUTPUT ---
    // performs write actions

val writer = new PrintWriter("myfile.txt")
writer.write("Writing line for line" + util.Properties.lineSeparator)
writer.write("Another line here" + util.Properties.lineSeparator)
writer.close()

Quickstart

// ----- QUICKSTART -----
    // Scala is statically typed but affords type inference (Scala compiler determines the type of a given variable if not explicitly defined)
    // a Scala program's entry point is defined within an object's main method
    // scalac => CLI command to compile the .scala file
    // val => declares an immutable value that cannot be reassigned
    // var => declares a mutable value that can be reassigned
    // : => declares the type of a variable

object Application { // object declaration
    def main(args: Array[String]): Unit = { // main method
        val x:Int = 10 
        x = 20 // this causes an error
        var y:Int = 10
        var z:Double = 1.0
        y = 20 // this is okay
        z = 2.5 // this is also okay
    }
}

Types

// ----- TYPE -----
    // Scala features a rich type system consisting of both primitive and complex types

// --- PRIMITIVE TYPE --- 
    // Byte => 8-bit signed integer
    // Short => 16-bit signed integer
    // Int => 32-bit signed integer
    // Long => 64-bit signed integer
    // Float => 32-bit single-precision floating point number
    // Double => 64-bit double-precision floating point number
    // Char => 16-bit Unicode character declared with '' single quotes
    // Boolean => true or false
    // Unit => represents the absence of a value with only one instance (), equivalent to void in Java

// --- REFERENCE TYPE ---
    // String => sequence of Char primitives, immutable and backed by the Java String class, declared with "" double quotes
    // Option => datatype representing either an optional value or None
    // Tuple => data structure storing a fixed number of items of different types, declared with () round brackets
    // List => immutable linked list
    // Seq => ordered sequence of elements
    // Set => unordered sequence of unique elements
    // Map => collection of key-value pairs

// --- ANY ---
    // Any => root type of all datatypes in Scala, allowing for Scala's type inference
    // AnyVal => parent type of all primitive types
    // AnyRef => parent type of all reference types

Operators

// ----- OPERATOR -----

// ARITHMETIC OPERATORS
    // + => addition
    // - => subtraction
    // * => multiplication
    // / => divison
    // % => modulo

// LOGICAL OPERATORS
    // && => logical and
    // || => logical or
    // ! => logical not

// COMPARISON OPERATORS
    // == => complete equality check for value and type
    // != => complete inequality check for value and type
    // .isInstanceOf[] => mostly used to check if object is of a specific type
    // >, <, >=, <= are comparison operators and operate as you'd expect

// ASSIGNMENT OPERATORS
    // = => simple assignment
    // += => increment by specified value and reassign
    // -= => decrement by specified value and reassign
    // *= => multiply by specified value and reassign
    // /= => divide by specified value and reassign

Control structures

// ----- CONTROL STRUCTURE -----

// ----- CONDITIONAL -----
    // conditionals can be specified for later evaluation within function calls and assignment statements
    // conditionals, like many other things in Scala, can also flexibly be written in a single line
        // if 
        // else
        // else if

val x:Int = 10
if (x == 1) println("this won't run")
if (x == 10) println("this will run")
if (x == 11) println("meanwhile this won't run") else if (x == 12) println("this also won't run") else println("but this will")
println(if (x == 10) "yeah" else "nope") // conditionals can be nested within other functions
val text = if (x == 10) "yeah" else "nope" // as well as assignment

// ----- LOOP -----
    // Scala does not feature 'conventional' for loops, but rather employs special keywords like to and by to generate similar structures
        // to => creates an iterable structure, equivalent of range in Python
        // by => specifies the step within the given iterable structure being created
    // .foreach() => equivalent of map() as a signature of functional programming, applies the given function call on a given iterable structure
        // this can be called without dots and brackets also, Scala is generally quite lenient with the function call syntax
    // while loop
        // while => specifies the predicate condition upon which the while loop runs a check on every iteration
    // do while loop
        // do => specify the action to be executed every loop iteration
        // while => specifies the predicate condition upon which the while loop runs a check on every iteration

val r = 1 to 5 // creates an iterable structure with Int's from 1 to 5 and assigns it to r
r.foreach(println) // prints "1\n2\n3\n4\n5\n" to the stdout
(5 to 1 by -1) foreach (println) // initialises an iterable structure literal and iterates over it and prints out each item accordingly

var i = 0
while (i < 10) { // classic while loop
    println("i " + i)
    i += 1 
}

i = 0
do {
    println("i is still less than 10") // classic do while loop
    i += 1
} while (i < 10)

Data structures

// ----- DATA STRUCTURE -----
    // () => declares a tuple with its specified element datatypes
    // Option[] => declares an option type that could either be the specified datatype or None
    // List[] => declared a linked list with elements of the specified type
    // Set[] => declares a set with elements of the specified type
    // Map[] => declares a Map with key-value pairs of the specified types
        // -> => specifies the relationship between a key-value pair

val tuple: (Int, String, Boolean) = (1, "Scala", true)
val someValue: Option[Int] = Some(5)
val noValue: Option[Int] = None
val list: List[Int] = List(1, 2, 3)
val set: Set[String] = Set("apple", "banana", "cherry")
val map: Map[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3)

Functions

// ----- FUNCTION -----
    // Scala features implicit return of the last expression within a function block, so there is no return keyword
        // the {} surrounding the function body can be omitted if the entire function body is a single expression that evaluates to the function's return value
    // def => defines a function similar to Python
    // : => specifies the datatype of a function's arguments and return values
    // = => used to assign default values to certain function arguments

def sumOfSquares(x: Int, y: Int): Int = {
    val x2 = x * x
    val y2 = y * y
    x2 + y2 // this last expression is implicitly returned
}

def sumOfSquaresShort(x: Int, y: Int): Int = x * x + y * y // this one-line function evaluates to the single return expression
def addWithDefault(x: Int, y: Int = 5) = x + y // default argument provided to this function

// --- ANONYMOUS FUNCTION ---
    // a hallmark of functional programming languages, where anonymous functions can be assigned to variables
    // => => defines an anonymous function and the relationship between the anonymous function's parameters and its return value
        // def and function name are completly omitted in anonymous function declarations

(x: Int) => x * x // this is an anonymous function
val sq: Int => Int = x => x * x // datatype of the anonymous function's parameters and return type can also be specified with this syntax which appears nearly identical to Haskell

Pattern Matching

// ----- PATTERN MATCHING -----
    // Scala features powerful pattern matching for multiple predicates that uniquely does not require breaks, fall-through simply does not occur
        // Scala even has regex support built in
    // match, case => creates a match-case expression that allows for pattern matching
        // => => specifies the relationship between a give case statement and the relevant execution code
        // _ => final catch-all character, equivalent of default in other languages

def matchPerson(person: Person): String = person match {
    case Person("George", number) => "We found George! His number is " + number
    case Person("Kate", number) => "We found Kate! Her number is " + number
    case Person(name, number) => "We matched someone : " + name + ", phone : " + number
}

def matchEverything(obj: Any): String = obj match { // this function's match statement takes in an object of any type
    case "Hello world" => "Got the string Hello world" // matches a value
    case x: Double => "Got a Double: " + x // match by type
    case x: Int if x > 10000 => "Got a pretty big number!" // matches a condition
    case Person(name, number) => s"Got contact info for $name!" // match the class of a case
    case email(name, domain) => s"Got email address $name@$domain" // match a regular expression
    case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c" // multiple matching within a tuple
    case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c" // match a data structure
    case List(List((1, 2, "YAY"))) => "Got a list of list of tuple" // nested patterns
    case _ => "Got unknown object" // match any uncaught case
}

More on