Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Scala Introduction
1. Scala
(Or how to have fun again as a server
side developer)
Adrian Spender
2. History Lesson: Java
• Developed by Sun Microsystems. Released in
1995
• Maintained and extended through the JCP
process
• Values backwards compatibility above all else
• Statically typed and OO
• Pace of change is slow and political
6. The JVM
• Execution environment for the Java bytecode
• A specification maintained through the JCP
• Comes in various implementations for a variety
of platforms, but guarantees binary compatibility
• Provides garbage collection, code validation and
much more
• Does not currently provide inherent support
for dynamic typing
8. The JVM runs more
than just Java
PHP
Javascript (Rhino)
JACL
C Erlang
9. History Lesson - Ruby
• Java is the compiled OO language of choice for server side development
in the enterprise (ignoring MSFT technologies)
• PHP, Python and other scripted languages rule the roost in the non-
enterprise
• Ruby aims to be the best of both worlds
• Released in 1996
• Dynamic typing
• Memory management
• OO, Functional, Imperative, Reflective styles
• Designed to be fun and productive to write in
• Excellent for rapid web apps thanks to the Rails framework
11. How Twitter killed
Ruby (or vice-versa)
• Twitter launched in 2006 - written almost
entirely in Ruby
• Exploded in popularity in 2007 and went
supernova in 2008
12.
13. Ok, so it wasn’t all
Ruby’s fault
• However, there’s no doubt that Ruby took a hit
• People questioned Ruby’s ability to scale
• A lot of Twitter’s problems were down to
how they had implemented message queues in
Ruby.
• “It's the heavy lifting, asynchronous processing
type of stuff that we've moved away from
[Ruby for].” - Alex Payne, Twitter developer
http://www.theregister.co.uk/2009/04/01/twitter_on_scala/
14. What did Twitter move
to?
http://www.artima.com/scalazine/articles/twitter_on_scala.html
15. What did Twitter move
to?
http://www.artima.com/scalazine/articles/twitter_on_scala.html
16. What is Scala?
• Designed by Martin Odersky - creator of the javac
compiler (from 1.3) and designer of Java’s generics
• Developed as an academic project at the Programming
Methods Lab at EPFL in Switzerland in 2003/4
• Is un-encumbered by corporate strategy or politics
• Is focussed much more on language evolution rather
than backwards compatibility
• Just received €2.3m in ERC funding to develop
language in the area of parallel processing. http://
www.scala-lang.org/node/8579
17. What is Scala?
• Runs on the JVM - compiles into Java bytecode
• Fast
• Scalable
• Interoperable with Java (and therefore any
Java technologies such and JDBC, JMS and so
on)
• General purpose
18. Scala popularity
• In the TIOBE 2010 programming Community Index Scala was the 50th most
popular language
• By comparison:
• 1 - Java
• 2-C
• 6 - C#
• 8 - Objective-C
• 10 - Ruby
• 11 - Javascript
• 23 - Object Pascal!!!
• 49 - Visual Basic .NET!!!
• But that isn’t the whole story...
http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
19. Scala popularity
• January 2011 Thoughtworks Radar report
identifies Scala as a “trial” technology
“Since the last radar we have realized
that the wider applicability of Scala
makes it more approachable for
enterprise developers, and we have
witnessed great successes in the
adoption of Scala.”
http://www.thoughtworks.com/radar
20. I can honestly say if someone had shown me the
Programming in Scala book by by Martin Odersky,
Lex Spoon & Bill Venners back in 2003 I'd probably
have never created Groovy.
James Strachan, creator of Groovy
http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for.html
Scala, it must be stated, is the current heir apparent
to the Java throne. No other language on the JVM
seems as capable of being a "replacement for Java" as
Scala, and the momentum behind Scala is now
unquestionable
Charles Nutter, creator of JRuby
http://blog.headius.com/2009/04/future-part-one.html
Q: Which programming language would you now use on top of the JVM,
other than Java?
James Gosling, creator of Java: Scala
http://www.adam-bien.com/roller/abien/entry/java_net_javaone_which_programming
21. Key characteristics
• Pure OO language
• Statically typed, but with type inference
• Powerful collections
• Encourages immutability (but doesn’t enforce)
• Supports imperative and functional styles
• First class pattern matching
• First class XML types
• Concurrency via actors
• DSLs
• Interoperates fully with Java
22. Scala > Java?
• Elegant, expressive, compact syntax
• Less boilerplate code
• More productivity
• Less maintenance
• Fewer runtime errors
• Much better concurrency
• If stuck, do it in Java - the best of both worlds!
29. Pure OO
• No primitive types
• Everything derives from base Any class
• No null, void
• No operators - just methods
• +, !=, :: are all examples of methods
• No static members
• First class singleton objects
• Single inheritance
• Traits (think interfaces with method implementations)
30. Pure OO
• Lots of syntactic sugar and magic to help
31. Pure OO
• Lots of syntactic sugar and magic to help
val x = 1
val y = x + 1
32. Pure OO
• Lots of syntactic sugar and magic to help
val x = 1
val y = x + 1
is actually
val x = 1
val y = x.+(1)
33. Pure OO
• Lots of syntactic sugar and magic to help
val x = 1 val square = (x: Int) => x * x
val y = x + 1 val x2 = square(2)
is actually
val x = 1
val y = x.+(1)
34. Pure OO
• Lots of syntactic sugar and magic to help
val x = 1 val square = (x: Int) => x * x
val y = x + 1 val x2 = square(2)
is actually is actually
val x = 1 val square = new Function1[Int, Int]() {
val y = x.+(1) def apply(x: Int) : Int = x * x
}
val x2 = square.apply(2)
35. Type Inference
Java:
List<String> list = new ArrayList<String>();
list.add("A");
list.add("list");
list.add("of");
list.add("strings");
36. Type Inference
Java:
List<String> list = new ArrayList<String>();
list.add("A");
list.add("list");
list.add("of");
list.add("strings");
Scala:
val list = List("A", "list", "of", "strings")
37. Type Inference
Java:
List<String> list = new ArrayList<String>();
list.add("A");
list.add("list");
list.add("of");
list.add("strings");
Scala:
val list = List("A", "list", "of", "strings")
val list2 = "Another" :: "list" :: "of" :: "strings" :: Nil
38. Classes
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}
39. Classes
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
} class Point (val x: Int, val y: Int) {
public int getX() { override def toString():
return x; String = "(" + x + ", " + y + ")";
} }
public int getY() {
return y;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}
40. Singletons
import scala.collection.mutable.Map
object PersonCache {
private val cache = Map[String, Person]()
def getPerson(id: String) : Person = {
if(cache.contains(id))
cache(id)
else {
val person = retrievePerson(id)
cache += (id -> person)
person
}
}
...
}
41. Companions
• A given class can have an associated companion
singleton object
• Must have the same name, in the same source file
• The companion object has full access to private
members of the class
• Most common use case is to act as a factory
• More advanced uses include definition of implicit
conversions
42. Traits
• Traits are like interfaces
• However they can have method
implementations
• Can be used as mixins
• Can do pretty much anything a class can
• Become a powerful method of code reuse
43. Traits
trait Animal {
def move() : String
def noise() : String
def breathe() = "In and out"
}
trait Swimmer {
def swim() = "Splish splosh"
}
trait Flyer {
def fly() = "Flap flap"
}
trait Walker {
def walk() =
"One leg in front of the other"
}
44. Traits
trait Animal { class Bird extends Animal with Flyer{
def move() : String def noise() = "Squark"
def noise() : String def move() = fly
}
def breathe() = "In and out"
} class Dog extends Animal with Walker {
def noise() = "Woof"
trait Swimmer {
def swim() = "Splish splosh" def move() = walk
} }
trait Flyer { class Fish extends Animal with Swimmer {
def fly() = "Flap flap" def noise() = "Glup glup"
}
def move() = swim
trait Walker { }
def walk() =
"One leg in front of the other" class Penguin extends Bird with Swimmer {
} override def move() = swim
}
46. Functional style
• Java is an imperative style
• Scala can do imperative but encourages functional
• Strongly encourages immutability
• If you have vars then you are being imperative
• Discourages functions with side effects
• If the return is Unit, then the function probably has
side effects
• Allows currying, higher-order functions, monads,
closures, tail recursion etc.
52. Functional
def fib(n: Int): BigInt = n match {
case 0 => 0
case 1 => 1
case _ => fib(n-1) + fib(n-2)
}
def genFibonacci(num: Int) : Array[BigInt] = {
Array.tabulate(num) (x => fib(x))
}
val sequence = genFibonacci(10)
print(sequence.mkString(" "))
53. More Functional!
lazy val fib: Stream[BigInt] = Stream.cons(0,
Stream.cons(1, fib.zip(fib.tail).map(
p => p._1 + p._2)))
def genFibonacci(num: Int) : Array[BigInt] = {
fib.take(num).toArray
}
val sequence = genFibonacci(10)
print(sequence.mkString(" "))
http://www.scala-blogs.org/2007/12/project-euler-fun-in-scala.html
54. Pattern matching
• Already seen one example:
def fib(n: Int): BigInt = n match {
case 0 => 0
case 1 => 1
case _ => fib(n-1) + fib(n-2)
}
• Scala can match against any object
def toRomanNumeralOne(n: Any): Option[String] = {
val numeral = "I"
n match {
case "I" => Some(numeral)
case 1 => Some(numeral)
case "one" => Some(numeral)
case _ => None
}
}
55. Case Classes
• A class with the keyword case gets the following for free:
• Constructor parameters become public fields
• toString, equals and hashCode implemented
• A singleton companion object
• Basically a factory
• Provides apply and unapply
• This makes it easy to define basic data objects
• All this also means they can be used in pattern matching
56. Remember this?
class Point (val x: Int, val y: Int) {
override def toString():
String = "(" + x + ", " + y + ")";
}
val point1 = new Point(1,2)
val x = point1.x
57. Remember this?
class Point (val x: Int, val y: Int) {
override def toString():
String = "(" + x + ", " + y + ")";
}
val point1 = new Point(1,2)
val x = point1.x
Using a case class we just need this:
case class Point (x: Int, y: Int)
val point2 = Point(1,2)
val x = point2.x
58. XML Types
case class Person(firstName: String, lastName:
String) {
def toXML =
<person>
<firstName>{ firstName }</firstName>
<lastName>{ lastName }</lastName>
</person>
def fromXML(node: scala.xml.Node): Person = {
new Person(
(node firstName).text,
(node lastName).text)
}
}
59. Actors
• Java uses a shared memory and lock based
concurrency model
• Scala uses an Actor based model made
popular by Erlang
• Actors communicate with each other by
passing messages
• Each actor receives (or reacts to)
messages and can send messages
60. Snap example
import scala.actors.Actor
import scala.actors.Actor._
case class Card(num: Int)
case object Snap
class Player(stack: Array[Card], player2: Option[Player]) extends Actor {
def this(stack: Array[Card], otherPlayer: Player) = this(stack, Some(otherPlayer))
def this(stack: Array[Card]) = this(stack, None)
def act() {
var round = 0
val name = player2 match {
case None => "Player 2"
case Some(player) =>
println("Player 1: Starts the game with " + stack(round))
player ! stack(round)
round += 1
"Player 1"
}
// Cont...
61. Snap example
while (round < stack.length) {
receive {
case card: Card =>
if (card == stack(round)) {
println(name + ": Snap!")
sender ! Snap
exit()
} else {
println(name + ": Plays " + stack(round))
sender ! stack(round)
}
case Snap =>
println(name + ": Well Played!")
exit()
}
round += 1
}
} // end of act method
}
62. Snap example
• Application:
object SnapGame {
val cards1 = Array(Card(0), Card(1), Card(2))
val cards2 = Array(Card(8), Card(7), Card(2))
val player2 = new Player(cards2)
val player1 = new Player(cards1, player2)
def main(args : Array[String]) : Unit = {
player1.start
player2.start
}
}
63. Snap example
• Output:
Player 1: Starts the game with Card(0)
Player 2: Plays Card(8)
Player 1: Plays Card(1)
Player 2: Plays Card(7)
Player 1: Plays Card(2)
Player 2: Snap!
Player 1: Well Played!
64. DSLs
• Domain Specific Language examples
• XSLT
• SQL
• WebSphere wsadmin
• Scala makes it easy to create new DSLs
• One good use of internal DSLs is in testing
65. Baysick
object Lunar extends Baysick {
def main(args:Array[String]) = {
10 PRINT "Welcome to Baysick Lunar Lander v0.9"
20 LET ('dist := 100)
30 LET ('v := 1)
40 LET ('fuel := 1000)
50 LET ('mass := 1000)
60 PRINT "You are drifting towards the moon."
70 PRINT "You must decide how much fuel to burn."
80 PRINT "To accelerate enter a positive number"
90 PRINT "To decelerate a negative"
100 PRINT "Distance " % 'dist % "km, " % "Velocity " % 'v % "km/s, " % "Fuel " % 'fuel
110 INPUT 'burn
120 IF ABS('burn) <= 'fuel THEN 150
130 PRINT "You don't have that much fuel"
140 GOTO 100
150 LET ('v := 'v + 'burn * 10 / ('fuel + 'mass))
160 LET ('fuel := 'fuel - ABS('burn))
170 LET ('dist := 'dist - 'v)
180 IF 'dist > 0 THEN 100
190 PRINT "You have hit the surface"
200 IF 'v < 3 THEN 240
210 PRINT "Hit surface too fast (" % 'v % ")km/s"
220 PRINT "You Crashed!"
230 GOTO 250
240 PRINT "Well done"
250 END
RUN
}
}
http://blog.fogus.me/2009/03/26/baysick-a-scala-dsl-implementing-basic/
66. Specs
class helloWorld extends Specification {
val hw = "hello world"
"'hello world' has 11 characters" in {
hw.size must be equalTo(11)
}
"'hello world' matches 'h.* w.*'" in {
helloWorld must be matching("h.* w.*")
}
}
http://code.google.com/p/specs/
67. Java interop
• Scala code can implement Java interfaces
• Scala code can call Java code
• This is generally very straightforward
• Java code can call Scala code
• This is sometimes more tricky if your Scala code uses language features that
don’t exist in Java
• May also need to understand what bytecode looks like e.g. a + operator
method ends up as in Java ( $plus )
• Differences between traits and interfaces
• Annotation differences/behaviour
• Exception behaviour
• Higher order functions
68. Cache sync example
package com.adrianspender.groupsync.java;
/**
* Provides methods to synchronize data stored locally in a
* persistent cache with the authoritative source.
*/
public interface GroupSyncService {
/**
* Retrieve the groups that the given person ID is in
* from the definitive resource, and update the
* persistent cache that we use ourselves.
*
* @param personId the id of the person to sync
*/
public void syncGroups(String personId);
}
69. Cache sync example
package com.adrianspender.groupsync.java;
import java.util.Set;
/**
* Represents some group service e.g. LDAP
*/
public interface AuthoritativeSource {
/**
* For a given person ID return the list of Group IDs that the person
* is in. If the user is in no groups, returns an empty set.
*
* @param personID the ID of the person
*
* @return the IDs of the groups the person is in
*/
public Set<String> getGroups(String personId);
}
70. Cache sync example
package com.adrianspender.groupsync.java;
import java.util.Set;
/**
* Represents our persistent cache. This would execute SQL
* queries against the DB.
*/
public interface PersistentCache {
/**
* Retrieve all of the groups that the given person is in, according
* to our cache. If the user is in no groups, then return an empty set
*
* @param personID the personID
*
* @return the IDs of the groups the cache thinks the person is in
*/
public Set<String> retrieveAllGroups(String personId);
/**
* Removes all of the groups from the cache for the given person
*
* @param personID the personID
*/
public void removeAllGroups(String personId);
// cont...
71. Cache sync example
/**
* Adds the newly joined groups to the cache for the given person.
*
* @param personID the person ID
*
* @param addedGroups the new groups that the person is in
*/
public void addNewGroups(String personId, Set<String> addedGroups);
/**
* Removes the newly removed groups from the cache for the given person.
*
* @param personID the person ID
*
* @param removedGroups the groups the person is no longer in
*/
public void removeGroups(String personId, Set<String> removedGroups);
}
72. Cache sync example
package com.adrianspender.groupsync.scala.impl
import com.adrianspender.groupsync.java._
import scala.collection.JavaConversions._
/*
* The Scala version of our group sync service..
*/
class GroupSyncServiceImpl(authoritativeSource: AuthoritativeSource,
persistentCache: PersistentCache) extends GroupSyncService {
def syncGroups(personId: String): Unit = {
val currentGroups = authoritativeSource.getGroups(personId).toSet
if (currentGroups.size() == 0) {
persistentCache.removeAllGroups(personId)
} else {
val cachedGroups = persistentCache.retrieveAllGroups(personId).toSet
persistentCache.addNewGroups(personId, currentGroups diff cachedGroups)
persistentCache.removeGroups(personId, cachedGroups diff currentGroups)
}
}
}
73. Cache sync example
• Scala implementation = 24 lines
• Java implementation = 47 lines
• Can be tested using JUnit
74. Tool Support
• IDE Support
• Eclipse, Intellij IDEA, NetBeans
• Build tools
• SBT
• But also ANT, Maven etc...
• Testing
• ScalaTest, Specs, ScalaCheck
• But also JUnit, EasyMock, Mockito etc...
• Web Frameworks
• Lift
• But also Struts, Spring MVC, Play etc...
• Actors
• Akka