Scala

Learned this for CS241E. Still feel like I don’t know what it does.

The name Scala stands for “scalable language.” The language is so named because it was designed to grow with the demands of its users.

Scala allows you to explore Functional Programming without completely disregarding Functional Programming without completely disregarding Object-Oriented Programming.

https://alvinalexander.com/scala/seq-class-methods-examples-syntax/

For some reason, tuples are 1-indexed, but everything else is 0-indexed.

  • var = variable
  • val = constant

Match case: https://alvinalexander.com/scala/how-to-use-if-then-expressions-guards-in-case-statements-scala/

Partial Function

First time I was exposed to this idea in scala.

val partialFunction: PartialFunction[Int, Int] = {  
case 1 => 100  
case 2 => 120  
case 3 => 130  
}
 
partialFunction.isDefinedAt(67) // Check if this argument will be accepted

Lazy Evaluation

val is executed when it is defined whereas a lazy val is executed when it is accessed the first time.

lazy val x = 5
x

Basics

// How to import library functions
import scala.io.StdIn.{readLine,readInt}
import scala.math._
 
var myName = "Derek" // Variable
val myAge = 40 // constant
val lastName: String = "Banas" // Specify type
for (i <- 1 to 10){ // 10 inclusive
  println(i)
}
 
// until stops one number before the final number
val randLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for (i <- 0 until randLetters.length){
  println(randLetters(i))
}
 
// Used to iterate through a list
val aList = List(1,2,3,4,5)
for(i <- aList){ println("List Item " + i) }
 
// Store even numbers in a list
var evenList = for { i <- 1 to 20 if (i % 2) == 0 } yield i
 
// This loop assigns a value to the 1st variable and it retains
// that value until the 2nd finishes its cycle and then it iterates
for (i <- 1 to 5; j <- 6 to 10){
  println("i: " + i)
  println("j: " + j)
}
 
// There is no break or continue in Scala
def printPrimes() {
  val primeList = List(1,2,3,5,7,11)
  for (i <- primeList){
 
	// Works like break if you return from a function
	if(i == 11){
	  return
	}
	// Works like continue
	if (i != 1){
	  println(i)
	}
  }
}

Function

// ---------- FUNCTIONS ----------
// def funcName (param1:dataType, param2:dataType) : returnType = {
//    function body
//    return valueToReturn
// }
 
// You can give parameters default values
def getSum( num1:Int = 1, num2:Int = 1) : Int = {
  return num1 + num2
}
 
println("5 + 4 = " + getSum(5,4))
 
// Receive variable number of arguments
def getSum2(args: Int*) : Int = {
  var sum : Int = 0
  for(num <- args){
    sum += num
  }
  sum
}
 
println("getSum2: " + getSum2(1,2,3,4,5))
 
// Recursion example calculating factorials
def factorial(num : BigInt) : BigInt = {
  if (num <= 1)
    1
  else
    num * factorial(num - 1)
}
 
// 1st: num = 4 * factorial(3) = 4 * 6 = 24
// 2nd: num = 3 * factorial(2) = 3 * 2 = 6
// 3rd: num = 2 * factorial(1) = 2 * 1 = 2
 
println("Factorial of 4 = " + factorial(4))
 
 

Array

Use Array when the size is fixed, or ArrayBuffer for a variable size array (Dynamic Array). There also is List

// ---------- ARRAYS ----------
val favNums = new Array[Int](20) // Array of size 20
val friends = Array("Bob", "Tom")
 
friends(0) = "Sue"
 
// Create an ArrayBuffer (Variable size array)
val friends2 = ArrayBuffer[String]()
 
friends2.insert(0, "Phil") // Insert an item to the 0th index
friends2 += "Mark" // Add item to the next available slot
friends2 ++= Array("Susy", "Paul") // Add multiple values to the next available slot
friends2.insert(1, "Mike", "Sally", "Sam", "Mary", "Sue") // Add items starting at 2nd slot
 
friends2.remove(1) // Remove the 2nd element
friends2.remove(1, 2) // Remove 2 elements starting at the 2nd index
 
// Add values to an array with a loop
for (j <- 0 to (favNums.length - 1)){
  favNums(j) = j
  println(favNums(j))
}
 
// Use yield to multiply all values times 2 and store in a new array
val favNumsTimes2 = for(num <- favNums) yield 2 * num
 
favNumsTimes2.foreach(println)  // print out values in array
 
// You can also store values that match a condition
var favNumsDiv4 = for(num <- favNums if num % 4 == 0) yield num
 
// Create a multidimensional array with Array.ofDim
var multTable = Array.ofDim[Int](10,10)
 
println("Sum : " + favNums.sum)
println("Min : " + favNums.min)
println("Max : " + favNums.max)
 
// Sorting in desending order (Use < for ascending)
val sortedNums = favNums.sortWith(_ > _)
 
// Return an indexed sequence and convert it into a string with commas
println(sortedNums.deep.mkString(", "))
 

List

val a = List("f", "fd", "fds")
a.tail // List("fd", "fds")
a.tail.tail // List("fds")
a.last // "fds"

Scala Map

I always get confused about these

// ---------- MAPS ----------
// Maps are collections of key value pairs
 
// Create a Map that can't be changed (Immutable)
val employees = Map("Manager" -> "Bob Smith", "Secretary" -> "Sue Brown")
 
// Get value using the key after checking that it exists
if(employees.contains("Manager"))
  printf("Manager : %s\n", employees("Manager"))
 
// Create a Mutable map
val customers = collection.mutable.Map(100 -> "Paul Smith",
  101 -> "Sally Smith")
 
printf("Cust 1 : %s\n", customers(100))
 
customers(100) = "Tom Marks" // Change a value using the key
customers(102) = "Megan Swift" // Add an item
 
// Output a Map
for((k,v) <- customers) {
  printf("%d : %s\n", k, v)
}

Tuple

Tuples can hold values of many types, but they are immutable

// ---------- TUPLES ----------
var tupleMarge = (103, "Marge Simpson", 10.25)
printf("%s owes us $%.2f\n", tupleMarge._2, tupleMarge._3)
 
// Iterate through a tuple
tupleMarge.productIterator.foreach{ i => println(i)}
println(tupleMarge.toString()) // Convert Tuple to String

Input / Output

// ---------- INPUT / OUTPUT ----------
var numberGuess = 0
do {
  print("Guess a number : ")
 
  // You can also use readInt, readDouble, readByte, readShort, readLong,
  numberGuess = readLine.toInt
  } while(numberGuess != 15)
 
printf("You guessed the secret number %d\n", 15)
 
// You can use string interpolation
val name = "Derek"
val age = 39
val weight = 175.5
println(s"Hello $name")
println(f"I am ${age + 1} and weigh $weight%.2f")
 
// printf Style Format Specifiers
// %c : Characters
// %d : Integers
// %f : Floating Point Numbers
// %s : Strings
printf("'%5d'\n",5) // Right justify
printf("'%-5d Hi'\n",5) // Left justify
printf("'%05d'\n",5) // Zero Fill
printf("'%.5f'\n",3.14) // 5 decimal minimum & maximum
printf("'%-5s'\n", "Hi") // Left Justify String
 
// Concatenate strings
println(randSent.concat(" and explode"))
 
// Compare strings for equality
println("Are strings equal " + "I saw a dragon".equals(randSent))
 
// Get index of a match
println("dragon starts at index ", randSent.indexOf("dragon"))
 
// Convert a string into an array
val randSentArray = randSent.toArray
 
for (v <- randSentArray)
  println(v)
 

Higher Order Functions

// ---------- HIGHER ORDER FUNCTIONS ----------
// Functions can be passed like any other variable
// You need the _ after the function to state you meant the function
val log10Func = log10 _
 
println(log10Func(1000))
 
// You can apply a function to all items of a list with map
List(1000.0,10000.0).map(log10Func).foreach(println)
 
// You can use an anonymous function with map as well
// Receives an Int x and multiplies every x by 50
List(1,2,3,4,5).map((x : Int) => x * 50).foreach(println)
 
// Filter will pass only those values that meet a condition
List(1,2,3,4,5,6).filter(_ % 2 == 0).foreach(println)
 
// Pass different functions to a function
def times3(num : Int) = num * 3
def times4(num : Int) = num * 4
 
// Define the function parameter type and return type
def multIt(func : (Int) => Double, num : Int ) = {
  func(num)
}
 
printf("3 * 100 = %.1f)\n", multIt(times3, 100))
 
// A closure is a function that depends on a variable declared outside
// of the function
val divisorVal = 5
val divisor5 = (num : Double) => num / divisorVal
println("5 / 5 = " + divisor5(5.0))
 
// ---------- FILE I/O ----------
// Use import java.io.PrintWriter to write to a file
val writer = new PrintWriter("test.txt")
writer.write("Just some random text\nSome more random text")
writer.close()
 
// Use import scala.io.Source to read from files
val textFromFile = Source.fromFile("test.txt", "UTF-8")
 
// Iterate through each line in the file and print
val lineIterator = textFromFile.getLines
for(line <- lineIterator){
  println(line)
}
textFromFile.close()
 

Exception Handling

// ---------- EXCEPTION HANDLING ----------
def divideNums(num1 : Int, num2 : Int) = try
{
  (num1 / num2)
} catch {
    case ex: java.lang.ArithmeticException => "Can't divide by zero"
} finally {
  // Clean up after exception here
}
 
println("3 / 0 = " + divideNums(3,0))
 
} // ---------- END OF MAIN ----------
 
 

Scala Classes

// ---------- CLASSES ----------
class Animal(var name : String, var sound : String) {
  this.setName(name)
 
  // Any code that follows the class name is executed each time an
  // object is created as part of the Primary Constructor
 
  // This function is defined in the Animal companion object below
  val id = Animal.newIdNum
 
  // You must initialize all fields
  // protected means the field can only be accessed directly by methods
  // defined in the class or by subclasses
  // private fields can't be accessed by subclasses of Animal
  // public fields can be accessed directly by anything
 
  // protected var name = "No Name"
  // protected var sound = "No Sound"
 
  // Getters and setters are used to protect data
  def getName() : String = name
  def getSound() : String = sound
  def setName(name : String){
    // Check if the String contains numbers and if so don't allow
    if(!(name.matches(".*\\ d+.*")))
 
      // this allows us to refer to any object without knowing its name
      this.name = name
    else
      this.name = "No Name"
  }
  def setSound(sound : String) {
    this.sound = sound
  }
 
  // Subclasses can't call this constructor unlike with Java
  def this (name : String){
 
    // This calls the primary constructor defined on the class line
    this("No Name", "No Sound")
    this.setName(name)
  }
 
  def this (){
    // This calls the primary constructor defined on the class line
    this("No Name", "No Sound")
  }
 
  // You can override any other method
  override def toString() : String = {
 
    // How to format Strings
    return "%s with the id %d says %s".format(this.name, this.id, this.sound)
  }
 
}
 
// The companion object for a class is where you'd define static class
// variables and functions in Java
object Animal {
  private var idNumber = 0
  private def newIdNum = { idNumber += 1; idNumber }
}
 
// ---------- CLASSES ----------
val rover = new Animal
rover.setName("Rover")
rover.setSound("Woof")
printf("%s says %s\n", rover.getName, rover.getSound)
 
val whiskers = new Animal("Whiskers", "Meow")
println(s"${whiskers.getName} with id ${whiskers.id} says ${whiskers.getSound}")
 
println(whiskers.toString)
 
val spike = new Dog("Spike", "Woof", "Grrrr")
 
spike.setName("Spike")
println(spike.toString)
 
val fang = new Wolf("Fang")
fang.moveSpeed = 36.0
println(fang.move)
 
// ---------- TRAITS ----------
val superman = new Superhero("Superman")
println(superman.fly)
println(superman.hitByBullet)
println(superman.ricochet(2500))
 
// ---------- INHERITANCE ----------
// A class that inherits from another gains all its fields and methods
// A class declared final can't be extended
class Dog (name : String, sound : String, growl : String) extends
Animal(name, sound){
 
  def this (name : String, sound : String){
    this("No Name", sound, "No Growl")
    this.setName(name)
  }
 
  def this (name : String){
    this("No Name", "No Sound", "No Growl")
    this.setName(name)
  }
 
  def this (){
    this("No Name", "No Sound", "No Growl")
  }
 
  // You can override any other method
  override def toString() : String = {
    return "%s with the id %d says %s or %s".format(
      this.name, this.id, this.sound, this.growl)
  }
}
 
// ---------- ABSTRACT CLASS ----------
// An abstract class can't be instantiated. It is made up of both abstract
// and non-abstract methods and fields
 
abstract class Mammal(val name : String){
  // An abstract field has no initial value
  var moveSpeed : Double
 
  // An abstract method has no body
  def move : String
 
}
 
class Wolf(name : String) extends Mammal(name){
  // You don't use override when defining abstract fields
  var moveSpeed = 35.0;
 
  def move = "The wolf %s runs %.2f mph".format(this.name, this.moveSpeed)
 
}

Trait

// ---------- TRAITS ----------
// A trait is a like a Java interface in that a class can extend more then 1
// Unlike Java interfaces traits can provide concrete methods and fields
trait Flyable {
  def fly : String
}
 
trait Bulletproof {
  def hitByBullet : String
 
  // You can define concrete methods in traits
  def ricochet(startSpeed : Double) : String = {
    "The bullet ricochets at a speed of %.1f ft/sec".format(startSpeed * .75)
  }
}
 
// The first trait starts with extends and then with for each other
class Superhero(val name : String) extends Flyable with Bulletproof{
  def fly = "%s flys through the air".format(this.name)
 
  def hitByBullet = "The bullet bounces off of %s".format(this.name)
}
 
}