2. HI!
I'm Kelsey.
I work at StackMob writing code that lets our users
create & manage their applications, APIs, and data
through the browser. I use Scala and the Lift web
framework to do that.
3. WHY ARE YOU HERE?
http://www.youtube.com/embed/Lb8BCl6NKn0
To learn to write code with drive that don't take no
jive.
4. THE PAM GRIER CRITERIA FOR
CODE BADASSERY
Code, like Pam Grier, should be:
Powerful,
Beautiful, and
Tough to mess with.
8. SCALA!
don't need parentheses for method calls
semicolons are optional
return value is the last line of the method
static typing with type inference
9. BUT WHAT DOES IT LOOK LIKE?
val x: String = "a"
val y = 2
val z = 15.3
val myThing = new Thing
val theList = List("this", "sure", "is", "a", "list")
val whatIsIt = theList(4)
10. BUT WHAT DOES IT LOOK LIKE?
def haggle(theirPrice: Int, myOffer: Int): String = {
val theResponse: String =
if (theirPrice <= myOffer + 5) {
"You've got a deal!"
} else {
"I definitely wouldn't pay more than " +
(myOffer + (theirPrice - myOffer)/2) +
" for it."
}
theResponse
}
val askingPrice = 100
val iWantToPay = 50
val letsMakeADeal = haggle(askingPrice, iWantToPay)
13. ASK A KID
(OR SIMPLE ENGLISH WIKIPEDIA)
A computer
program is a list
WRONG
of instructions
that tell a
computer what to
do.
14. Imperative programming:
a sequence of commands that the computer carries
out in sequence
Object-oriented programming:
these instructions, and the data they manipulate, are
organized into objects
15. If a program's not a series of commands, then
what is it?
16.
17. “Functional programming is a style of
programming that emphasizes the
evaluation of expressions rather than
the execution of commands.”
—comp.lang.functional FAQ
18. WHAT THINGS ARE
val theQueen = "Elizabeth II"
but also...
def theGovernor(state: State) = {
val candidates = state.getCandidates
candidates(getTopVoteGetter)
}
19. WHAT IS A FUNCTION?
A function is a relation
between values where
each of its input values
gives back exactly one
output value, playa.
21. A function is pure if “the impact of a function on the
rest of the program [can] be described only in terms of
its return type, and...the impact of the rest of the
program on the function be described only in terms of
its arguments”. (Victor Nicollet)
23. FUNCTIONS ARE DETERMINISTIC.
You will always get the same result if you run them
with the same data.
correctness is more clear
unit tests are a breeze
debugging is more directed
tough to mess with
24. FUNCTIONS ARE ENCAPSULATED.
“With a referentially transparent function, the interface-
level activity is all one needs to know about its
behavior.”. (Michael O. Church)
readability
reuse
maintainability
beautiful
tough to mess with
25. FUNCTIONS ARE COMMUTATIVE.
val firstThing = doOneThing()
val secondThing = doAnotherThing()
val thirdThing = doTheLastThing(firstThing, secondThing)
parallelization
concurrency
lazy evaluation
powerful
26. DATA IS IMMUTABLE.
Once an object is created, it cannot be changed.
If you need to change an object, make your own
copy.
a quick detour back to Java...
String s1 = "san dimas high school football rules"
String s2 = s1.toUpperCase
println("string 1: " + s1);
println("string 2: " + s2);
concurrency
rollback of data
simplicity
powerful tough to mess with
30. FIRST CLASS CITIZENS
val longSkinnyThing: String = "this is a string"
val listOfThem: List[String] = List("yarn","twine","thread")
val freshNewLongSkinnyThing: String = spinFromFiber("wool")
tieInAKnot(longSkinnyThing)
class Rope(type:String) {
override def toString(): String = "You've put me on a diet!";
}
val longSkinnyThing: Rope = new Rope("nautical")
val listOfThem: List[String] =
List(longSkinnyThing, new Rope("climbing"),
new Rope("clothesline"), new Rope("jump"))
val freshNewLongSkinnyThing: Rope = spinFromFiber("hemp")
tieInAKnot(longSkinnyThing)
31. val addSpam: (String) => String =
{ (x:String) => x + " and Spam" }
addSpam("Egg and Bacon")
//result: "Egg and Bacon and Spam"
val menuOptions = List(addSpam, withoutSpam)
menuOptions(1)("Egg and Bacon and Spam")
//result: "You can't have that"
addSpam's type is (String) => String
(list of parameters' types) => return
type
32. RETURNING FUNCTIONS FROM
FUNCTIONS
def tagText(tag: String, text: String) = "<" + tag +">" + text +
""
val noReally = tagText("em", "pay attention!!!!")
//result: <em>pay attention!!!!</em>
def tagText2(tag: String) = { (text:String) =>"<" + tag +">" + te
xt + "" }
val tagWithAndSpam = tagText2("andSpam")
val breakfast = tagWithAndSpam("Spam Bacon and Sausage")
//result: <andSpam>Spam Bacon and Sausage</andSpam>
beautiful
powerful
35. FOR LOOP
Java
public void talkAboutFruit {
Fruit[] fruits = {
new Fruit("apple"),
new Fruit("cherry"),
new Fruit("strawberry")
};
for (int i = 0; i < fruits.length; i++) {
System.out.println("Hey the other day I ate a " +
fruits[i];
}
}
Scala
def talkAboutFruit = {
val fruits = List(new Fruit("apple"),
new Fruit("cherry"),
new Fruit("strawberry"))
for (i <- 0 until fruits.length) {
System.out.println("Hey the other day I ate a " +
fruits(i);
}
}
36. LET'S GET ABSTRACT
a function that takes a list and a function
(list of parameters' types) => return type
foreach(fruitList:List(fruits),
theFunction: (Fruit) => Unit): Unit
def foreach(fruitList:List(fruits), theFunction: (Fruit) => Unit
) = {
for (i <- 0 until fruitList.length) {
theFunction(fruits(i))
}
}
def talkAboutFruit = {
val fruits = List(new Fruit("apple"),
new Fruit("cherry"),
new Fruit("strawberry"))
val tellEm =
{ (f:Fruit) => System.out.println(
"Hey the other day I ate a " + f) }
foreach(fruits, tellEm)
}
}
37. MORE ABSTRACTERER!
foreach(theList:List(A), theFunction:
(A) => Unit): Unit
abstract class Collection[A] {
...
def foreach(theFunction: (A) => Unit): Unit
...
}
def talkAboutFruit = {
val fruits = List(new Fruit("apple"),
new Fruit("cherry"),
new Fruit("strawberry"))
val tellEm =
{ (f:Fruit) => System.out.println(
"Hey the other day I ate a " + f) }
fruits.foreach(tellEm)
}
}
38. THIS:
abstract class Collection[A] {
...
def foreach(theFunction: (A) => Unit): Unit = {
for (i <- 0 until this.length) {
theFunction(this(i))
}
}
...
}
IS NOT HOW SCALA
IMPLEMENTED FOREACH
tough to mess with
powerful
39. SOMETHING A LITTLE JUICIER
def makePies: List[Pie] = {
val fruits = List(new Fruit("apple"),
new Fruit("cherry"),
new Fruit("strawberry"))
var pies = List()
for (i <- 0 until fruits.length) {
new Pie(fruits(i)) :: pies
}
pies
}
on a collection of A, you can
map(theFunction: (A) => B):
Collection[B]
def makePies: List[Pie] = {
val fruits = List(new Fruit("apple"),
new Fruit("cherry"),
new Fruit("strawberry"))
val makePie = { (f: Fruit) => new Pie(f) }
fruits.map(makePie)
}
40. ANONYMOUS FUNCTIONS
val kindOfFruit: String = "blueberry"
val blueberryFruit = new Fruit(kindOfFruit)
val alsoBlueberry = new Fruit("blueberry")
val makePie = { (f: Fruit) => new Pie(f) }
fruits.map(makePie)
//equivalent to
fruits.map( { (f: Fruit) => new Pie(f) } )
def makePies: List[Pie] = {
val fruits = List(new Fruit("apple"),
new Fruit("cherry"),
new Fruit("strawberry"))
fruits.map( { (f: Fruit) => new Pie(f) } )
}
def makePies(fruits: List[Fruit]) : List[Pie]
= fruits.map( { (f: Fruit) => new Pie(f) } )
beautiful
41. COLLECTION HANDLING
FILTER
val theList = List(new Fruit("apple"), new Fruit("pear"), new Fru
it("cherry"), new Fruit("strawberry"), new Fruit("honeydew"))
scala> theList.filter( { (f: Fruit) => f.isDelicious } )
res0: List[Fruit] = List(apple, cherry, strawberry)
FOLD
scala> theList.fold("The fruits on this list are: ")( { (stringSo
Far: String, f: Fruit) => stringSoFar + " " + f.name } )
res1: String = "The fruits on this list are: apple pear cherry st
rawberry honeydew"
REDUCE
scala> theList.fold(0)( { (count: Int, f: Fruit) => count + " " +
f.totalPieces } )
res2: Int = 42300
theList.reduce( { (f: Fruit) => f.totalPieces } )
res3: Int = 42300
42. NESTED FOR-LOOPS
def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):
List(Serving[Pie, IceCream]) {
val servings = List[Serving[Pie,IceCream]]()
for (p <- 0 until pies.length) {
for (i <- 0 until iceCreams.length) {
val serving = new Serving(p, i)
serving :: servings
}
}
servings
}
def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):
List(Serving[Pie, IceCream]) {
pies.map( { (p: Pie) =>
iceCreams.map( { (i: IceCream) =>
new Serving(p, i)
} )
} )
}
43. IS THIS AN IMPROVEMENT?
def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]): L
ist(Serving[Pie, IceCream]) {
val servingsLists =
pies.map( { (p: Pie) =>
iceCreams.map( { (i: IceCream) =>
new Serving(p, i)
} )
} )
servingsLists.flatten
}
44. FUNCTION COMPOSITION
def bakeAPie(f: Fruit, c: Crust): Pie
def eatAPie(p: Pie): HappyKelsey
def bakeAndEatAPie(f: Fruit, c: Crust): HappyKelsey = eatAPie com
pose bakeAPie
//could also be written bakeAPie andThen eatAPie
flatten compose map is flatMap, and it's MAGIC
45. FOR-YIELD
def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):
List(Serving[Pie, IceCream]) {
for {
p <- pies
i <- iceCreams
} yield {
new Serving(p,i)
}
}
beautiful!
46. FUN WITH FOR-YIELD
def goodPairings(pies: List[Pie], iceCreams: List[IceCream]): Li
st(Serving[Pie, IceCream]) {
for {
p <- pies
i <- iceCreams
val serving = new Serving(p,i)
if (serving.isGood)
} yield {
serving
}
}
def pleaseEverybody(audience: List[Person], pies: List[Pie], ice
Creams: List[IceCream]): List(ThankYou) {
for {
person <- audience
p <- pies
i <- iceCreams
val serving = new Serving(p,i)
if (serving.isGood)
} yield {
person.feed(serving)
}
}
51. OPTION
Option[T] is either a Some with a value of type T
inside, or None representing nothing.
val someOption: Option[String] = Some("this is a value")
val noneOption: Option[String] = None
val theSomeValue = someOption.get //returns "this is a value"
val someIsDefined = someOption.isDefined //returns true
val theNoneValue = noneOption.get //throws NoSuchElementException
val someIsDefined = someOption.isDefined //returns false
53. OPTION IS KIND OF LIKE A
COLLECTION
.MAP
someOption.map( {(str:String) => str + " SAN DIMAS HIGH SCHOOL FO
OTBALL RULES"} )
//returns Some("this is a value SAN DIMAS HIGH SCHOOL FOO
TBALL RULES")
noneOption.map( {(str:String) => str + " SAN DIMAS HIGH SCHOOL FO
OTBALL RULES"} )
//returns None
.FLATMAP
val favoritePie: Option[Pie] = Some(rhubarb)
favoritePie.map({ (pie: Pie) => pairings.get(pie) })
//returns Some(Some(butterPecan))--whoops!
favoritePie.flatMap( { (pie: Pie) => pairings.get(pie) } )
//returns Some(butterPecan)
.FILTER
val todaysSpecial: Option[Pie]
val myOrder = todaysSpecial.filter( { (pie: Pie) => (pie != butte
rPecan) }
54. FOR-YIELD OVER OPTION
for {
pie <- todaysSpecial
bestIceCream <- pairings.get(pie)
iceCream <- availableFlavors.get(bestIceCream) } yield {
myDessert
}
beautiful
powerful
tough to mess with
56. "Let’s look at what it is that makes Thing a monad.
The first thing is that I can wrap up a value inside of a
new Thing...We have a function of type A => Thing; a
function which takes some value and wraps it up
inside a new Thing.
We also have this fancy bind function, which digs
inside our Thing and allows a function which we
supply to use that value to create a new Thing. Scala
calls this function “flatMap“....
What’s interesting here is the fact that bind is how
you combine two things together in sequence. We
start with one thing and use its value to compute a
new thing."
—Daniel Spiewak
57. FLATMAP IS MAGIC
flatMap hides our boilerplate. For Lists, it abstracts
away a for-loop, letting us create a new List from an
existing list. For Options, it abstracts away a null
check, letting us create a new nullable value from an
existing one.
tough to mess with
62. READABILITY
“Is Clojure code hard to understand? Imagine if every
time you read Java source code and encountered
syntax elements like if statements, for loops, and
anonymous classes, you had to pause and puzzle
over what they mean. There are certain things that
must be obvious to a person who wants to be a
productive Java developer. Likewise there are parts
of Clojure syntax that must be obvious for one to
efficiently read and understand code. Examples
include being comfortable with the use of let, apply,
map, filter, reduce and anonymous functions...”—R.
Mark Volkmann
63. DSLS
class HelloWorldSpec extends Specification {
"The 'Hello world' string" should {
"contain 11 characters" in {
"Hello world" must have size(11)
}
"start with 'Hello'" in {
"Hello world" must startWith("Hello")
}
"end with 'world'" in {
"Hello world" must endWith("world")
}
}
}
from specs2
64. PURITY
“The truth is that good programmers mix the styles quite
a bit. We program imperatively when needed, and
functionally when possible.” - Michael O. Church