Created by @jmarinotero
For more, see this
Approach to systems architecture to meet modern demands
This means no shared state, easier to read and write concurrently
Code can be sent where the data is
Doing some work on an array in Javascript
var i;
for(i = 0; i < someArray.length; i++) {
var someThing = someArray[i];
doSomeWorkOn(someThing);
}
Much better with the underscore.js library:
_.each(someArray, doSomeWorkOn);
class Point {
private int x;
private int y;
public Point(int x, int y) {
setX(x);
setY(y);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public boolean equals(Object other) {
if (other instanceof Point) {
Point otherPoint = (Point) other;
return otherPoint.getX() == getX() &&
otherPoint.getY() == getY();
} else {
return false;
}
}
@Override
public int hashCode() {
return (new Integer[] {getX(), getY()}).hashCode();
}
}
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if isinstance(other, Point):
return other.x == self.x and other.y == self.y
else:
return False
def __hash__(self):
return hash((self.x, self.y))
case class Point(var x: Int, var y: Int)
val x = 1 + 2 * 3 // The type of x is Int
val y = x.toString // The type of y is String
def add(x:Int) = x + 1 // Add returns Int values
val x = 2 // Declare immutable variable
x = 3 // error: reassignment to val
val geometry: Geometry = ...
geometry match {
case p:Point => println(s"$p.x, $p.y")
case line:Line => println(line.length)
case poly:Polygon => println(poly.perimeter)
}
val points:List[Point] = ...
val polygon: Polygon = ...
// If point is inside polygon, print it
points.foreach(p => if polygon.contains(p) println(p))
// Create a buffer around each point, return that collection of polygons
points.map(p => p.buffer(1.0))
// Buffer points that are inside the polygon
points.map { p =>
val pt = polygon.contains(p)
pt.buffer(1.0)
}
Make sure you understand things like the following before writing them
From 10 Scala One Liners to Impress Your Friends:
// Filter list of numbers into two categories based on a criteria
val (passed, failed) = List(49, 58, 76, 82, 88, 90) partition ( _ > 60 )
// Sum list of numbers
(1 to 1000).reduceLeft( _ + _ )
// Sieve of Eratosthenes, algorithm to calculate if a number is prime
(n: Int) => (2 to n) |> (r => r.foldLeft(r.toSet)((ps, x) => if (ps(x)) ps -- (x * x to n by x) else ps))
It's also beautiful if you understand it
Automatically mark all emails from my mom as read in my inbox
emails.filter(_.isNotSpam).filter(_.sender == "Mom").map(_.copy(isRead = true))
Or using a for comprehension
for {
notSpam <- emails if emails.isNotSpam == true
momEmails <- notSpam if emails.sender == "Mom"
read <- notSpam.copy(isRead = true)
} yield read
A computer programming language of limited expressiveness focused on a particular domain (Martin Fowler, 2010)
Scala is great for defining your own language. Example from ScalaTest:
import collection.mutable.Stack
import org.scalatest._
class ExampleSpec extends FlatSpec with Matchers {
"A Stack" should "pop values in last-in-first-out order" in {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
stack.pop() should be (2)
stack.pop() should be (1)
}
it should "throw NoSuchElementException if an empty stack is popped" in {
val emptyStack = new Stack[Int]
a [NoSuchElementException] should be thrownBy {
emptyStack.pop()
}
}
}
This is where Scala really shines
import scala.concurrent._
import scala.concurrent.duration._
def main(args: Array[String]) {
val rateQuote = future {
connection.getCurrentValue(USD)
}
val purchase = rateQuote map { quote =>
if (isProfitable(quote)) connection.buy(amount, quote)
else throw new Exception("not profitable")
}
Await.result(purchase, 0 nanos) // THIS BLOCKS! (use only for testing)
}
import scala.util.{Success, Failure}
val f: List[Future[Double]] = future {
connection.getCurrentValues(USD, EUR)
}
f onComplete {
case Success(quotes) => for (quote <- quotes) println(quote)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
Avoid callbacks in nested future calls (callback hell)
val usdQuote = future { connection.getCurrentValue(USD) }
val chfQuote = future { connection.getCurrentValue(CHF) }
val purchase = for {
usd <- usdQuote
eur <- chfQuote
if isProfitable(usd, eur)
} yield connection.buy(amount, eur)
purchase onSuccess {
case _ => println("Purchased " + amount + " EUR")
}
def slowCalcFuture: Future[Int] = ... // 01
def combined: Future[Int] = async { // 02
await(slowCalcFuture) + await(slowCalcFuture) // 03
}
val x: Int = Await.result(combined, 10.seconds) // 05
In this example, lines 1-4 are non-blocking, but not parallel. To parallelize both computations:
def combined: Future[Int] = async {
val future1 = slowCalcFuture
val future2 = slowCalcFuture
await(future1) + await(future2)
}
val array = (1 to 100000).toArray
array.par.reduce(_ + _)
Note: the advantages of this are only visible in large collections
Main implementation in the Akka library
Akka is a toolkit and runtime for building highly concurrent, distributed, and resilient message-driven applications on the JVM.An actor is a primitive that can make local decisions, create more actors, send more messages, and determine how to respond to the next message received
Very small memory footprint: ~2.5 million / GB of memory
import akka.actor.{ActorSystem, Actor, ActorLogging, Props }
case class Greeting(who: String)
class GreetingActor extends Actor with ActorLogging {
def receive = {
case Greeting(who) ⇒ log.info("Hello " + who)
}
}
val system = ActorSystem("MySystem")
val greeter = system.actorOf(Props[GreetingActor], name = "greeter")
greeter ! Greeting("Mr. Smith")
def receive = {
case Greeting(who) ⇒ log.info("Hello " + who)
}
greeter ! Greeting("Mr. Smith")
def receive: Receive = {
case Greeting(who) => sender() ! "Hello, " + who
}
val f:Future[String] = greeter ? Greeting("Mr Smith")
Both are asynchronous and non blocking(*)
Remote and local process actors treated the same
Unified programming model for multicore and distributed computing
Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure on the JVM.
A good read: Queues don't fix overload
import akka.actor.ActorSystem
import akka.stream.ActorFlowMaterializer
import akka.stream.scaladsl.Source
object BasicTransformation {
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem("Sys")
import system.dispatcher
implicit val materializer = ActorFlowMaterializer()
val text =
"""|Lorem Ipsum is simply dummy text of the printing and typesetting industry.
|Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
|specimen book.""".stripMargin
Source(() => text.split("\\s").iterator).
map(_.toUpperCase).
runForeach(println).
onComplete(_ => system.shutdown())
}
}
GET / controllers.Application.index()
GET /foo controllers.Application.foo()
def index() {
Ok(views.html.index("Scala Play Demo"))
}
@(title: String)(content: Html)
<html>
<head>
@title
</head>
<body>
@content
</body>
</html>
def echoWs = WebSocket.using[String] { request =>
val (enumerator, channel) = Concurrent.broadcast[String]
val in = Iteratee.foreach[String](channel.push)
(in, enumerator)
}
$ ->
ws = new WebSocket("ws://localhost:9000/echo")
ws.onopen = () ->
ws.send("foo")
ws.onmessage = (message) ->
console.log(message.data)
Also, it's 10 - 100x faster than Hadoop