In February of 2011 I gave a talk about Scala at a Seattle Tech Startups meeting at the University of Washington. My original slides from that talk are here: A Brief Intro To Scala (PPTX).
Since most of the content is still relevant, I thought it would be fun to update it a bit and convert it to a reveal.js presentation.
You can see a full browser window version here or an embedded version below (press f
for full screen on either one):
A Brief Intro to Scala
Tim Underwood
About Me
- Tim Underwood
- Software Developer with 20+ years of experience
- Perl, PHP C, C++, C#, Java, Ruby, Scala
- ~15 years of Scala experience
- Before Scala default languages were Ruby and Java
Dynamic vs. Static
Dynamic (Ruby) | Static (Java) |
---|---|
|
|
Scala
Best of both worlds!Dynamic-Like | Static |
---|---|
|
|
Scalable language
Scala is a modern multi-paradigm programming language designed to express common programming patterns in a concise elegant and type-safe way.
Scala
- Statically Typed
- Runs on JVM, full inter-op with Java
- Object Oriented
- Functional
- Dynamic Features
Scala is Practical
- Can be used as drop-in replacement for Java
- Mixed Scala/Java projects
- Use existing Java Libraries
- Use existing Java tools (Ant, Maven, JUnit, etc.)
- Decent IDE Support (IntelliJ)
Scala is Concise
Type Inference
val sum = 1 + 2 + 3 // Int
val lst = List(1, 2, 3) // List[Int]
val map = Map("abc" -> List(1,2,3)) // Map[String, List[Int]]
Explicit Types
val sum: Int = 1 + 2 + 3
val lst: List[Int] = List(1, 2, 3)
val map: Map[String, List[Int]] = Map("abc" -> List(1,2,3))
Higher Level
Java (pre lambdas)// Check if string has uppercase character
boolean hasUpperCase = false;
for(int i = 0; i < name.length(); i++) {
if(Character.isUpperCase(name.charAt(i))) {
hasUpperCase = true;
break;
}
}
Higher Level
Scala// Check if string has uppercase character
val hasUpperCase = name.exists(_.isUpperCase)
Less Boilerplate
Java - Mutable POJOpublic class Person {
private String name;
private int age;
public Person(String name, Int age) { // constructor
this.name = name;
this.age = age;
}
public String getName() { // name getter
return name;
}
public int getAge() { // age getter
return age;
}
public void setName(String name) { // name setter
this.name = name;
}
public void setAge(int age) { // age setter
this.age = age;
}
}
Less Boilerplate
Scala - Mutable Classclass Person(var name: String, var age: Int)
Less Boilerplate
Scala
Override Getter and/or Setter as-needed
class Person(var name: String, private var _age: Int) {
def age = _age // Getter for age
def age_=(newAge:Int) { // Setter for age
println("Changing age to: "+newAge)
_age = newAge
}
}
Variables and Values
var - can reassign val - only assign once
// variable
var foo = "foo"
// this is fine since foo is a var
foo = "bar"
// value
val bar = "bar" // Java equivalent: final String bar = "bar"
// does not compile since bar is a val
bar = "foo"
Scala is Object Oriented
Pure O.O.
// Every value is an object
1.toString
// Every operation is a method call
1 + 2 + 3 <=> (1).+(2).+(3)
// Can omit . and ( )
"abc" charAt 1 <=> "abc".charAt(1)
Classes
// Classes (and abstract classes) like Java
abstract class Language(val name: String) {
override def toString = name
}
// Example implementations
class Scala extends Language("Scala")
// Anonymous class
val scala = new Language("Scala") { /* add stuff here */ }
Traits
// Like interfaces in Java
trait Language {
val name: String
// But allow implementation
override def toString = name
}
Traits
trait JVM {
override def toString = super.toString+" runs on JVM" }
trait Static {
override def toString = super.toString+" and is Static" }
// Traits are stackable
class Scala extends Language with JVM with Static {
val name = "Scala"
}
println(new Scala) // "Scala runs on JVM and is Static"
Singleton Objects
// Replaces static methods from Java
// Can extend/implement classes & traits
object Hello {
def world = println("Hello World"}
}
Hello.world // Prints: Hello World
Scala is Functional
First Class Functions
// Create anonymous function
val plusOne = (x: Int) => x + 1
// Calling the anonymous function
plusOne(5)
Closures
var foo = 1
// plusFoo can reference any values/variables in scope
val plusFoo = (x: Int) => x + foo
plusFoo(5) // 6
// Changing foo changes the return value of plusFoo
foo = 5
plusFoo(5) // 10
Higher Order Functions
val plusOne = (x: Int) => x + 1
val nums = List(1,2,3)
// map takes a function: Int => T
nums.map(plusOne) // List(2,3,4)
// Inline Anonymous
nums.map(x => x + 1) // List(2,3,4)
// Short form using a placeholder
nums.map(_ + 1) // List(2,3,4)
Higher Order Functions
val nums = List(1,2,3,4)
// A few more examples for List class
nums.exists(_ == 2) // true
nums.find(_ == 2) // Some(2)
nums.indexWhere(_ == 2) // 1
nums.reduceLeft(_ + _) // 10
nums.foldLeft(100)(_ + _) // 110
// Many more in collections library
Higher Order Functions
// functions as parameters
def call(f: Int => Int) = f(1)
call(plusOne) // 2
call(x => x + 1) // 2
call(_ + 1) // 2
Higher Order Functions
// functions as parameters
def each(xs: List[Int], fun: Int => Unit): Unit = {
if (!xs.isEmpty) {
fun(xs.head)
each(xs.tail, fun) // tail recursion is optimized!
}
}
each(List(1,2,3), println)
// 1
// 2
// 3
Higher Order Functions
Using generics & pattern matchingdef each[T](xs: List[T], fun: T => Unit): Unit = xs match {
case Nil =>
case head :: tail => fun(head); each(tail, fun)
}
each(List(1,2), println)
// 1
// 2
each(List("foo", "bar"), println)
// foo
// bar
Pattern Matching
def what(any: Any) = any match {
case i: Int => "It's an Int"
case s: String => "It's a String"
case _ => "I don't know what it is"
}
what(123) // "It's an Int"
what("hello") // "It's a String"
what(false) // "I don't know what it is"
Pattern Matching
val nums = List(1,2,3)
// Pattern matching to create 3 vals
val List(a,b,c) = nums
a // 1
b // 2
c // 3
Immutable Types
// Immutable types by default
var nums = Set(1,2,3)
nums += 4 // nums = nums.+(4) -- creates new set
// Mutable types available
import scala.collection.mutable._
val nums = Set(1,2,3)
nums += 4 // nums.+=(4) -- updates existing set
scala.collection
scala.collection.immutable
scala.collection.mutable
Or Use Existing Java Collections
- java.util
- Apache Commons Collections
- fastutil (my favorite!)
- Eclipse Collections
- Google Guava
Scala is Dynamic*
(*Okay not really, but it has lots of features typically only found in Dynamic languages)
Scala is Scriptable
bash$ cat hello.sc
println("Hello, World!")
bash$ scala-cli hello.sc
Hello, World!
Read-Eval-Print Loop
bash$ scala
Welcome to Scala 3.3.1 (17, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> class Foo { def bar = "baz" }
// defined class Foo
scala> val f = new Foo
val f: Foo = Foo@213835b6
scala> f.bar
val res0: String = baz
Structural Typing
Type-Safe Duck Typingimport reflect.Selectable.reflectiveSelectable
def doTalk(any: {def talk: String}) = {
println(any.talk)
}
class Duck { def talk = "Quack" }
class Dog { def talk = "Bark" }
doTalk(new Duck) // "Quack"
doTalk(new Dog) // "Bark"
Implicit Conversions
Extend existing classes in a type-safe way// Goal: Add isBlank method to String class
implicit class RichString(s: String) {
def isBlank = null == s || "" == s.trim
}
// Our isBlank method is now available on Strings!
" ".isBlank // true
"foo".isBlank // false
Implicit Conversions
How it works at a high level// 1. Does not type check
"abc".isBlank // ERROR
// 2. Search in-scope implicits classes and methods that take
// a String and return a type with an isBlank method
implicit class RichString(s: String) { def isBlank = ... }
// 3. Scala converts the code to:
new RichString("abc").isBlank
method_missing
import scala.language.dynamics
class Foo extends Dynamic {
def applyDynamic(name: String)(args: Any*) = {
println("called: "+name+"("+args.mkString(",")+")")
}
}
val f = new Foo
f.helloWorld() // called: helloWorld()
f.hello("world") // called: hello(world)
f.bar(1,2,3) // called: bar(1,2,3)
Scala has tons of other cool stuff!
Default Parameter Values
def hello(foo: Int = 0, bar: Int = 0) = {
println("foo: "+foo+" bar: "+bar)
}
hello() // foo: 0 bar: 0
hello(1) // foo: 1 bar: 0
hello(1,2) // foo: 1 bar: 2
Named Parameters
def hello(foo: Int = 0, bar: Int = 0) = {
println("foo: "+foo+" bar: "+bar)
}
hello(bar = 6) // foo: 0 bar: 6
hello(foo = 7) // foo: 7 bar: 0
hello(foo = 8, bar = 9) // foo: 8 bar: 9
Everything Returns a Value
val a = if (true) "yes" else "no"
val b = try {
"foo"
} catch {
case _ => "error"
}
val c = {
println("hello")
"foo"
}
Lazy Vals
// initialized on first access
lazy val foo = {
println("init")
"bar"
}
foo // init
foo //
foo //
Nested Functions
def outer() = {
var msg = "foo"
def one() = {
def two() = {
println(msg)
}
two()
}
one()
}
By-Name Parameters
def log(doLog: Boolean, msg: => String) {
if (doLog) {
msg // evaluates msg
msg // evaluates msg again!
}
}
def foo: String = { println("in foo"); "Foo" }
log(true, foo+" Bar") // foo called twice
log(false, foo+" Bar") // foo never called
Many More Features
@foo def hello = "world" // annotations
case class Foo(bar: String) // case classes
def foo(a: Int)(b: Boolean) // currying
fun(123, _) // partially applied functions
(1, "foo", false) // tuples
for (i <- 1 to 5 if i % 2 == 0) yield i // for comprehensions
Personal Experiences
- Productive from Day 1
- Drop in replacement for Java giving you more Ruby-like syntax and features
- Can pickup the functional and higher-level programming concepts as you go
- implicits are very powerful (when used properly)

www.scala-lang.org
A Brief Intro to Scala Tim Underwood
Note: This was previously posted on the old Startup Monkeys Blog but that site no longer exists.