Railroading into Scala

35
railroading into scala a really fast guide for Java developers Inspired by Gilt Tech’s Scala Course

Transcript of Railroading into Scala

railroading into scala

a really fast guide for Java developers

Inspired by Gilt Tech’s Scala Course

scala basics

● Runs on the JVM● Fully object-oriented, no primitives● Fully supports functional programming● Interpreted or compiled to Java bytecode

syntax

● Less verbose than Java● No semi-colons (except multi-statement

lines)● Type declaration after identifier:

○ val myVar: Int = 10● Unit = void

syntax

● Declarations○ def for functions○ val for immutables○ var for mutables○ lazy val executes at first access, intended for

expensive operations:lazy val fib = fibonacci(10)

expressions

● Everything is an expression● No "return" needed, last statement is the

return value● Anonymous function:

(parameters) => return_type =

{ argument => return_value }

expressions

(Int) => String = { i => "Number " + i }

val x = if (total == 30) {

"Total is 30"

} else {

"Total is something else"

}

loops

● for-loopfor (arg <- args) {

println(arg)

}

for (i <- 0 to 10 by 2) {

println(i)

}

loops

● for-comprehensionval ints = for (arg <- args) yield {

arg.toInt

}

for {

i <- 0 to 2

j <- 1 to 3

} yield {i * j}

functions

● First-class citizens● Can be returned from a function● Can be assigned to a val ● Can be nested● Can have anonymous functions

options

● To get around nulls, Scala gives us Option● 2 states: Some and None● Test with .isDefined and .isEmpty ● get() returns the value if Some, else throws

exception● orElse() and getOrElse() for None

options

Some(“Hello”).isDefined

// res0: Boolean = true

None.getOrElse(“Nothing!”)

// res0: String = Nothing!

exceptions

● No checked exceptions● Catch matches exceptions by type

exceptions

try{}

catch{

case nfe: NumberFormatException => println("Not a number")

case oom: OutOfMemoryException => println("Out of memory")

}

finally{}

REPL (Read-Eval-Print-Loop)

● sbt console or sbt console-quick or scala

● You can import packages as well● :paste

classes

● Abstract classes and traits● Only one primary constructor, ancillary

constructors possible: def this(...)● Members are public by default● Nothing vs. Null types● def can be overridden by val

classes

trait Shape {

def area: Double

}

class Circle(val radius: Double) extends Shape {

override val area = math.Pi * radius

val circumference = 2 * math.Pi * radius

}

val c = new Circle(1)

c.radius // res0: Double = 1.0

c.area // res1: Double = 3.141592653589793

c.circumference // res2: Double = 6.283185307179586

classes

class ModifiableRectangle(var x: Double, var y: Double) extends Shape {

def this(x: Double) = this(x, x)

override def area = x * y

}

class ModifiableSquare(a: Double) extends ModifiableRectangle(a, a) {

private val originalArea = a * a

}

traits

● Similar to interfaces, but can have default implementation

● No constructor● Multiple inheritance: initialize left to right,

linearize right to left

traitstrait IntStack {

def pop(): Option[Int]

def push(x: Int): Unit

def isEmpty: Boolean

}

class BasicStack extends IntStack {

private val stack = new collection.mutable.Stack[Int]()

override def pop(): Option[Int] = {

if (stack.empty()) { None }

else { Some(stack.pop()) }

}

override def push(x: Int): Unit = stack.push(x)

override def isEmpty = stack.empty

}

traitstrait Doubling extends IntStack {

abstract override def push(x: Int): Unit = super.push(x * 2)

}

trait Incrementing extends IntStack {

abstract override def push(x: int): Unit = super.push(x + 1)

}

class MyStack extends BasicStack with Doubling with Incrementing

class YourStack extends BasicStack with Incrementing with Doubling

val me = new MyStack()

me.push(2)

me.pop

// res0: Option[Int] = Some(6)

val you = new YourStack()

you.push(2)

you.pop

// res0: Option[Int] = Some(5)

objects

● Equivalent to static class● May extend/implement a class or trait

(singleton)

companion object

● Same name as companion class, same file● Equivalent to static methods● May apply() methods

companion object

class MyStack extends BasicStack

object MyStack {

def apply(): MyStack = new MyStack()

def apply(ints: Int*): MyStack = {

val stack = new MyStack()

ints.foreach(stack.push(_))

stack

}

}

val myStack = new MyStack()

val yourStack = MyStack()

val ourStack = MyStack(1, 2, 3, 4)

enumerations

● Extend scala.Enumeration● Values have inner type Enumeration.Value

object Color extends Enumeration {

val Red, Green, Blue = Value

}

val red = Color.Red

Java Scala

Interface Trait

Abstract Class Trait or Abstract Class

Class Class

Object/Instance Object/Instance

Static Class, Singleton Object

Static Members Companion Object

Enum Enumeration

case classes

● Implements hashCode, equals, and toString methods

● Add companion object with apply()● Implements copy()● Great for pattern matching!

immutability

● val vs. var● Reduce side effects● Concurrency issues● Transform data vs. update data

collections

● Immutable vs. mutable collections

lists

● Construction: List(1, 2, 3), List.empty[String], List[String] = Nil

● Access: myList(2)● Concatenation: myList ::: otherList, 0 ::

myList, myList :+ 4● Update: myList.updated(1, 9)● isEmpty

● head, tail, init, last● headOption, lastOption● take, drop, slice● toString, mkString● contains, exists, forall (return Boolean)● find (returns Option)

lists

sets and maps

● Construction: Set(1, 2, 3)● Combination:

○ mySet ++ Set(5, 6, 7)○ myMap ++ Map("three" -> 3)

● Insert: ○ mySet + 9○ myMap + ("three" -> 3)

● Access: myMap.get("one")

monads

map def map[B](f: A => B): List[B]

flatMap def flatMap[B](f: A => List[B]): List[B]

filter def filter(f: A => Boolean): List[A]

higher order functions

foldLeftdef foldLeft[B](z: B)(op: (B, A) = B): BList(1, 2, 3, 4).foldLeft(0)({ (a: Int, b: Int) => a + b })

collect(1 until 100).toList.collect {

case i if (i % 2 == 0) => "even"

case _ => "odd"

}

higher order functions

groupByList("one", "two", "three", "four", "five").groupBy(a => a.size)

partition(1 until 10).toList.partition(_ % 2 == 0)