0
Pragmatic
Real-World Scala

             Jonas Bonér
       Scalable Solutions
“If I were to pick a language
to use today other than Java,
it would be Scala”
                 James Gosling
Chat app in Lift
    Build a multi-user, comet-based chat app




    About 30 lines of code




    Three slides worth
...
Define Messages
case class Add(who: Actor)
case class Remove(who: Actor)
case class Messages(msgs: List[String])
Chat Server
object ChatServer extends Actor {
  private var listeners: List[Actor] = Nil
  private var msgs: List[String] ...
Chat Comet Component
class Chat extends CometActor {
  private var msgs: List[String] = Nil
  def render =
    <div>
     ...
Demo
Scalable language
Unique and elegant blend of



OO FP           +
2003
                            Since
              Pragmatic
                 Sponsored by EPFL
Martin Odersky
      Sea...
Unique and elegant blend of



       is...
Expressive &
       light-weight
val phonebook = Map(
  “Jonas” -> “123456”,
  “Sara” -> “654321”)
phonebook += (“Jacob” -...
High-level
            Java version
boolean hasUpperCase = false;
for (int i = 0; i < name.length(); i++) {
  if (Characte...
High-level
             Scala version

val hasUpperCase = name.exists(_.isUpperCase)
Concise
// Java
public class Person {
 private String name;
 private int age;
 public Person(String name,
                ...
Pure OO
1+2
1.+(2)

123.toString()
Extensible
val service = actor {
  loop {
    receive {
      case Add(x,y) => reply(x+y)
      case Sub(x,y) => reply(x-y...
Pragmatic
def users =
  <users>
    <user role=”customer”>
      <name>{ user.name }</name>
      <password>{ user.passwor...
Pragmatic
users match {
  case <users>{users @ _*}</users> =>
    for (user <- users)
      println(“User “ + (user  “name...
Great for DSLs
     Apache Camel
“direct:a“ ==> {
  loadbalance roundrobin {
    to (“mock:a“)
    to (“mock:b“)
    to (“...
deep
 Scala is
But you don’t need to go very deep
to still have fun and be productive
Java
Tastier Java
Different beast
Composition
Composition

     large
in
2
building blocks
Traits
       &
   &


  Self-type
annotations
Trait
trait Dad {
  private var children: List[Child] = Nil

    def addChild(child: Child) =
      children = child :: ch...
Base

class Man(val name: String) extends Human
Plumbing
Static mixin composition

class Man(val name: String) extends Human with Dad
Static mixin composition
          usage
class Man(val name: String) extends Human with Dad


val jonas = new Man(“Jonas”)...
Dynamic mixin composition


val jonas = new Man(“Jonas”) with Dad
Dynamic mixin composition
         usage
val jonas = new Man(“Jonas”) with Dad


jonas.addChild(new Child(“Jacob”))
3   different type of traits
1
Rich interface
trait RichIterable[A] {
  def iterator: Iterator[A] // contract method

    def foreach(f: A => Unit) = {
 ...
Rich interface
val richSet =
    new java.util.HashSet[Int]
    with RichIterable[Int]

richSet.add(1)
richSet.add(2)

ric...
2
Stackable modifications
trait IgnoreCaseSet
  extends java.util.Set[String] {

    abstract override def add(e: String) = ...
Stackable modifications
val set =
    new java.util.HashSet[String]
    with IgnoreCaseSet

set.add(“HI THERE“)      // up...
Add another trait interceptor
trait LoggableSet
  extends java.util.Set[String] {

    abstract override def add(e: String...
Run the stack of interceptors
  val set =
    new java.util.HashSet[String]
    with IgnoreCaseSet
    with LoggableSet

 ...
Change the order
val set =
  new java.util.HashSet[String]
  with LoggableSet
  with IgnoreCaseSet

set.add(“HI THERE“)
  ...
3
Multiple views
    Trait                   Trait




Trait                         Trait
             Base




           ...
Multiple views
    Trait                   Trait




Trait                         Trait
             Base




           ...
Traits
 Multiple
personalities
Traits


          Multiple
         facets
Base
class Order(val cust: Customer)
Facets
trait   Entity { ... }
trait   InventoryItemSet { ... }
trait   Invoicable { ... }
trait   PurchaseLimiter { ... }
...
Composition
val order = new Order(customer)
    with Entity
    with InventoryItemSet
    with Invoicable
    with Purchas...
What do you
  need?
DI
this: <deps> =>
this: <deps> =>
Dependency declaration
trait UserService {
  this: UserRepository =>
  ...
  // provided with composition
  userRepository...
Duck typing
walks like a duck…
   if it

   and talks like a duck…

   then it’s a duck

Duck typing
Structural Typing:
      Duck-typing done right
def authorize(target: { def getACL: ACL }) = {

    val acl = target.getAC...
Composition

   in small
“It's Time to Get Good at
 Functional Programming”
                   Dr Dobb’s Journal
                Issue December 2008
What’s
all the

buzz
about?
Deterministic
               Reusable
High-level

        FP      Referentially
                transparent

Immutable    ...
Lego
FP is like
Small reusable pieces

       input
with



       output
and
Unix pipes

cat File | grep 'println' | wc
Functions

(x: Int) => x + 1
Functions as values
  val inc = (x: Int) => x + 1


  inc(1)   2
Functions as parameters
         high-order
List(1, 2, 3).map((x: Int) => x + 1)

    List(2, 3, 4)
Functions as parameters
          with sugar
List(1, 2, 3).map((x: Int) => x + 1)


List(1, 2, 3).map(x => x + 1)


List(1...
Functions as closures

val addMore = (x: Int) => x + more
more?
What is
Some value outside
the function’s lexical scope
 var more = 7
 val addMore = (x: Int) => x + more


 addMore(3)  10
 more...
Functional
Data Structures
Immutable
The almighty




List
Lists
Grow at the front
Insert at front  O(1)
Insert at end  O(n)
List creation
  List(1, 2, 3)


1 :: 2 :: 3 :: Nil
Basics
val list = List(1, 2, 3)
list.head    1
list.tail     List(2, 3)
list.isEmpty  false
High-level operations
val list = List(1, 2, 3)
list.map(_ + 1)      List(2,   3, 4)
list.filter(_ < 2)  List(3)
list.exi...
115
                       List
functions defined on
Tuples
def getNameAndAge: Tuple2[String, Int] = {
  val name = ...
  val age = ...
  (name, age)
}


val (name, age) = get...
Other
functional data structures:
                   Maps
                    Sets
                  Trees
               ...
For comprehensions

  for (n <- names)
    println(n)
Like SQL queries
for {
  att <- attendees
  if att.name == “Fred”
  lang <- att.spokenLanguages
  if lang == “Danish”
} pr...
for / yield
val companiesForAttendeesFromLondon =
  for {
    att <- attendees
    if att.address.city == “London”
  } yie...
Everything returns a value


    for (thing <- thingsFromHere)
    yield getRealThing(thing)
Everything returns a value


   val things =
     for (thing <- thingsFromHere)
     yield getRealThing(thing)
Everything returns a value


   if (fromHere) {
     for (thing <- thingsFromHere)
     yield getRealThing(thing)
   } els...
Everything returns a value

 val things =
   if (fromHere) {
     for (thing <- thingsFromHere)
     yield getRealThing(th...
Everything returns a value

  try {
    if (fromHere) {
      for (thing <- thingsFromHere)
      yield getRealThing(thing...
Everything returns a value
val things =
  try {
    if (fromHere) {
      for (thing <- thingsFromHere)
      yield getRea...
Everything returns a value
def getThingsFromSomewhere(
  fromHere: Boolean): List[Thing] = {
  try {
    if (fromHere) {
 ...
Pattern
matching
Pattern matching
def matchAny(a: Any): Any = a match {
  case 1                => “one”
  case “two”            => 2
  cas...
Tools
Tools: scala/bin
            scala
           scalac
               fsc
        scaladoc
             sbaz
Tools: IDEs
        Eclipse
    NetBeans
 IntelliJ IDEA
         Emacs
           JEdit
Building
             Maven
               Ant
SBT (Simple Build Tool )
Tools: Testing
          Specs
    ScalaCheck
      ScalaTest
          SUnit
Frameworks: Web
            Lift
           Sweet
           Slinky
            Pinky
Learn more
jonas@jonasboner.com
  http://jonasboner.com
     http://scala-lang.org
Professional help
Consulting Training Mentoring

    http://scalablesolutions.se
Pragmatic
Real-World Scala

              Jonas Bonér
       Scalable Solutions


        Copyright 2009 Scalable Solutions
Pragmatic Real-World Scala
Upcoming SlideShare
Loading in...5
×

Pragmatic Real-World Scala

1,330

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,330
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
65
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Transcript of "Pragmatic Real-World Scala"

  1. 1. Pragmatic Real-World Scala Jonas Bonér Scalable Solutions
  2. 2. “If I were to pick a language to use today other than Java, it would be Scala” James Gosling
  3. 3. Chat app in Lift Build a multi-user, comet-based chat app  About 30 lines of code  Three slides worth  Slides By David Pollak, creator of Lift 
  4. 4. Define Messages case class Add(who: Actor) case class Remove(who: Actor) case class Messages(msgs: List[String])
  5. 5. Chat Server object ChatServer extends Actor { private var listeners: List[Actor] = Nil private var msgs: List[String] = Nil def act = loop { react { case s: String => msgs = s :: msgs listeners.foreach(l => l ! Messages(msgs)) case Add(who) => listeners = who :: listeners who ! Messages(msgs) case Remove(who) => listeners -= who } } this.start }
  6. 6. Chat Comet Component class Chat extends CometActor { private var msgs: List[String] = Nil def render = <div> <ul>{ msgs.reverse.map(m => <li>{ m }</li>) }</ul> { ajaxText(quot;quot;, s => { ChatServer ! s; Noop }) } </div> override def localSetup = ChatServer ! Add(this) override def localShutdown = ChatServer ! Remove(this) override def lowPriority = { case Messages(m) => msgs = m; reRender(false) } }
  7. 7. Demo
  8. 8. Scalable language
  9. 9. Unique and elegant blend of OO FP +
  10. 10. 2003 Since Pragmatic Sponsored by EPFL Martin Odersky Seamless Java interoperability Friendly and supportive Production community ready Statically typed JVM Runs on the
  11. 11. Unique and elegant blend of is...
  12. 12. Expressive & light-weight val phonebook = Map( “Jonas” -> “123456”, “Sara” -> “654321”) phonebook += (“Jacob” -> “987654”) println(phonebook(“Jonas”))
  13. 13. High-level Java version boolean hasUpperCase = false; for (int i = 0; i < name.length(); i++) { if (Character.isUpperCase(name.charAt(i))) { hasUpperCase = true; break; } }
  14. 14. High-level Scala version val hasUpperCase = name.exists(_.isUpperCase)
  15. 15. Concise // Java public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; // Scala this.age = age; } class Person( public String getName() { var name: String, return name; } var age: Int) public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(age: int) { this.age = age; } }
  16. 16. Pure OO 1+2 1.+(2) 123.toString()
  17. 17. Extensible val service = actor { loop { receive { case Add(x,y) => reply(x+y) case Sub(x,y) => reply(x-y) } } } 6 service ! Add(4, 2)
  18. 18. Pragmatic def users = <users> <user role=”customer”> <name>{ user.name }</name> <password>{ user.password }</password> <email>{ user.email }</email> </user> ... </users>
  19. 19. Pragmatic users match { case <users>{users @ _*}</users> => for (user <- users) println(“User “ + (user “name”).text) }
  20. 20. Great for DSLs Apache Camel “direct:a“ ==> { loadbalance roundrobin { to (“mock:a“) to (“mock:b“) to (“mock:c“) } }
  21. 21. deep Scala is
  22. 22. But you don’t need to go very deep to still have fun and be productive
  23. 23. Java
  24. 24. Tastier Java
  25. 25. Different beast
  26. 26. Composition
  27. 27. Composition large in
  28. 28. 2 building blocks
  29. 29. Traits & & Self-type annotations
  30. 30. Trait trait Dad { private var children: List[Child] = Nil def addChild(child: Child) = children = child :: children def getChildren = children.clone }
  31. 31. Base class Man(val name: String) extends Human
  32. 32. Plumbing
  33. 33. Static mixin composition class Man(val name: String) extends Human with Dad
  34. 34. Static mixin composition usage class Man(val name: String) extends Human with Dad val jonas = new Man(“Jonas”) jonas.addChild(new Child(“Jacob”))
  35. 35. Dynamic mixin composition val jonas = new Man(“Jonas”) with Dad
  36. 36. Dynamic mixin composition usage val jonas = new Man(“Jonas”) with Dad jonas.addChild(new Child(“Jacob”))
  37. 37. 3 different type of traits
  38. 38. 1
  39. 39. Rich interface trait RichIterable[A] { def iterator: Iterator[A] // contract method def foreach(f: A => Unit) = { val iter = iterator while (iter.hasNext) f(iter.next) } def foldLeft[B](seed: B)(f: (B, A) => B) = { var result = seed foreach(e => result = f(result, e)) result } }
  40. 40. Rich interface val richSet = new java.util.HashSet[Int] with RichIterable[Int] richSet.add(1) richSet.add(2) richSet.foldLeft(0)((x, y) => x + y) 3
  41. 41. 2
  42. 42. Stackable modifications trait IgnoreCaseSet extends java.util.Set[String] { abstract override def add(e: String) = { super.add(e.toLowerCase) } abstract override def contains(e: String) = { super.contains(e.toLowerCase) } abstract override def remove(e: String) = { super.remove(e.toLowerCase) } }
  43. 43. Stackable modifications val set = new java.util.HashSet[String] with IgnoreCaseSet set.add(“HI THERE“) // uppercase set.contains(“hi there“) // lowercase  true
  44. 44. Add another trait interceptor trait LoggableSet extends java.util.Set[String] { abstract override def add(e: String) = { println(“Add :“ + e) super.add(e) } abstract override def remove(e: String) = { println(“Remove :“ + e) super.remove(e) } }
  45. 45. Run the stack of interceptors val set = new java.util.HashSet[String] with IgnoreCaseSet with LoggableSet set.add(“HI THERE“)  “Add: HI THERE” Prints in uppercase
  46. 46. Change the order val set = new java.util.HashSet[String] with LoggableSet with IgnoreCaseSet set.add(“HI THERE“)  “Add: hi there” Prints in lowercase
  47. 47. 3
  48. 48. Multiple views Trait Trait Trait Trait Base Trait
  49. 49. Multiple views Trait Trait Trait Trait Base Trait
  50. 50. Traits Multiple personalities
  51. 51. Traits Multiple facets
  52. 52. Base class Order(val cust: Customer)
  53. 53. Facets trait Entity { ... } trait InventoryItemSet { ... } trait Invoicable { ... } trait PurchaseLimiter { ... } trait MailNotifier { ... } trait ACL { ... } trait Versioned { ... } trait Transactional { ... }
  54. 54. Composition val order = new Order(customer) with Entity with InventoryItemSet with Invoicable with PurchaseLimiter with MailNotifier with ACL with Versioned with Transactional
  55. 55. What do you need?
  56. 56. DI
  57. 57. this: <deps> =>
  58. 58. this: <deps> =>
  59. 59. Dependency declaration trait UserService { this: UserRepository => ... // provided with composition userRepository.merge(user) } …using self-type annotation
  60. 60. Duck typing
  61. 61. walks like a duck… if it and talks like a duck… then it’s a duck Duck typing
  62. 62. Structural Typing: Duck-typing done right def authorize(target: { def getACL: ACL }) = { val acl = target.getACL ... //authorize } Statically enforced
  63. 63. Composition in small
  64. 64. “It's Time to Get Good at Functional Programming” Dr Dobb’s Journal Issue December 2008
  65. 65. What’s all the buzz about?
  66. 66. Deterministic Reusable High-level FP Referentially transparent Immutable Declarative Orthogonal
  67. 67. Lego FP is like
  68. 68. Small reusable pieces input with output and
  69. 69. Unix pipes cat File | grep 'println' | wc
  70. 70. Functions (x: Int) => x + 1
  71. 71. Functions as values val inc = (x: Int) => x + 1 inc(1) 2
  72. 72. Functions as parameters high-order List(1, 2, 3).map((x: Int) => x + 1)  List(2, 3, 4)
  73. 73. Functions as parameters with sugar List(1, 2, 3).map((x: Int) => x + 1) List(1, 2, 3).map(x => x + 1) List(1, 2, 3).map(_ + 1)
  74. 74. Functions as closures val addMore = (x: Int) => x + more
  75. 75. more? What is
  76. 76. Some value outside the function’s lexical scope var more = 7 val addMore = (x: Int) => x + more addMore(3)  10 more = 8 addMore(3)  11
  77. 77. Functional Data Structures
  78. 78. Immutable
  79. 79. The almighty List
  80. 80. Lists Grow at the front Insert at front  O(1) Insert at end  O(n)
  81. 81. List creation List(1, 2, 3) 1 :: 2 :: 3 :: Nil
  82. 82. Basics val list = List(1, 2, 3) list.head 1 list.tail  List(2, 3) list.isEmpty  false
  83. 83. High-level operations val list = List(1, 2, 3) list.map(_ + 1)  List(2, 3, 4) list.filter(_ < 2)  List(3) list.exists(_ == 3)  true list.drop(2)  List(3) list.reverse  List(3, 2, 1) list.sort(_ > _)  List(3, 2, 1) List.flatten(list)  List(1, 2, 3) list.slice(2, 3)  List(3) ...
  84. 84. 115 List functions defined on
  85. 85. Tuples def getNameAndAge: Tuple2[String, Int] = { val name = ... val age = ... (name, age) } val (name, age) = getNameAndAge println(“Name: “ + name) println(“Age: “ + age)
  86. 86. Other functional data structures: Maps Sets Trees Stacks
  87. 87. For comprehensions for (n <- names) println(n)
  88. 88. Like SQL queries for { att <- attendees if att.name == “Fred” lang <- att.spokenLanguages if lang == “Danish” } println(att) Find all attendees named Fred that speaks Danish
  89. 89. for / yield val companiesForAttendeesFromLondon = for { att <- attendees if att.address.city == “London” } yield att.company
  90. 90. Everything returns a value for (thing <- thingsFromHere) yield getRealThing(thing)
  91. 91. Everything returns a value val things = for (thing <- thingsFromHere) yield getRealThing(thing)
  92. 92. Everything returns a value if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { for (thing <- thingsFromThere) yield thing }
  93. 93. Everything returns a value val things = if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { for (thing <- thingsFromThere) yield thing }
  94. 94. Everything returns a value try { if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { for (thing <- thingsFromThere) yield thing } } catch { case e => error(e); Nil }
  95. 95. Everything returns a value val things = try { if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { for (thing <- thingsFromThere) yield thing } } catch { case e => error(e); Nil }
  96. 96. Everything returns a value def getThingsFromSomewhere( fromHere: Boolean): List[Thing] = { try { if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { for (thing <- thingsFromThere) yield thing } } catch { case e => error(e); Nil } }
  97. 97. Pattern matching
  98. 98. Pattern matching def matchAny(a: Any): Any = a match { case 1 => “one” case “two” => 2 case i: Int => “scala.Int” case <tag>{ t }</tag> => t case head :: tail => head case _ => “default” }
  99. 99. Tools
  100. 100. Tools: scala/bin scala scalac fsc scaladoc sbaz
  101. 101. Tools: IDEs Eclipse NetBeans IntelliJ IDEA Emacs JEdit
  102. 102. Building Maven Ant SBT (Simple Build Tool )
  103. 103. Tools: Testing Specs ScalaCheck ScalaTest SUnit
  104. 104. Frameworks: Web Lift Sweet Slinky Pinky
  105. 105. Learn more jonas@jonasboner.com http://jonasboner.com http://scala-lang.org
  106. 106. Professional help Consulting Training Mentoring http://scalablesolutions.se
  107. 107. Pragmatic Real-World Scala Jonas Bonér Scalable Solutions Copyright 2009 Scalable Solutions
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×