Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scala: The Pointy Bits

Scala: The Pointy Bits

The pared down version of "Scala: The Swiss Army Language" encompassing just the parts that could get you into trouble on day 1 of a dive into an existing, mature Scala codebase.

Avatar for Nathan Dotz

Nathan Dotz

May 29, 2015
Tweet

More Decks by Nathan Dotz

Other Decks in Programming

Transcript

  1. scala> var t = "Hello variables" t: String = Hello

    variables scala> t = "Hello reassignment" t: String = Hello reassignment VAR
  2. scala> var x = 5 x: Int = 5 scala>

    def g = x g: Int scala> g res1: Int = 5 scala> x = 6 x: Int = 6 scala> g res2: Int = 6
  3. scala> def exclaim(s: String) = s + "!!!" exclaim: (s:

    String)String scala> exclaim("Hello, Scala") res3: String = Hello, Scala!!!
  4. def exclaim = { s:String => println(s) s + "!!!"

    } exclaim: String => String CURLY = BLOCK
  5. scala> def exclaim(s:String) = { | println(s) | s +

    "!!!" | } exclaim: (s: String)String scala> { s: String => println(s); s + "!!!" } res0: String => String = <function1> scala> exclaim("Hello, Scala") Hello, Scala res1: String = Hello, Scala!!! scala> res0("Hello, Scala") Hello, Scala res2: String = Hello, Scala!!!
  6. scala> { s: String => println(s); s + "!!!" }

    res0: String => String = <function1> scala> exclaim("Hello, Scala") Hello, Scala res1: String = Hello, Scala!!! scala> res0("Hello, Scala") Hello, Scala res2: String = Hello, Scala!!! FAT ARROW = FUNCTION
  7. scala> { s: String => println(s); s + "!!!" }

    res0: String => String = <function1> scala> exclaim("Hello, Scala") Hello, Scala res1: String = Hello, Scala!!! scala> res0("Hello, Scala") Hello, Scala res2: String = Hello, Scala!!! FAT ARROW = FUNCTION
  8. scala> res2.toList res3: List[Char] = List(H, e, l, l, o,

    ,, , S, c, a, l, a, !, !, !) TYPE PARAMETERS a List of Chars
  9. scala> val s = "Hello, Scala" s: String = Hello,

    Scala scala> s + "!!!" == s.+("!!!") res0: Boolean = true DSL SYNTAX
  10. scala> val s = "Hello, Scala" s: String = Hello,

    Scala scala> s + "!!!" == s.+("!!!") res0: Boolean = true DSL SYNTAX
  11. val s = "Hello Scala" var t = "Hello variables"

    final String s = "Hello Scala"; String t = "Hello variables";
  12. var x = 5 def g = x g x

    = 6 g int x = 5; int getX() { return x; } getX(); x = 6; getX();
  13. def exclaim(s:String) = { println(s) s + "!!!" } String

    exclaim(String s) { System.out.println(s); return s + "!!!"; }
  14. scala> val f = { s: String => s +

    "!!!" } f: String => String = <function1> scala> f("hi") res0: String = hi!!!
  15. scala> val f = { s: String => s +

    "!!!" } f: String => String = <function1> scala> f("hi") res0: String = hi!!! scala> { s: String => s + "!!!" }.apply("Hello, Scala") res1: String = Hello, Scala!!!
  16. scala> { s: String => s + "!!!" }.apply("Hello, Scala")

    res1: String = Hello, Scala!!! public abstract class Function1<T, R> { public R apply(T t); } final Function1<String, String> f = new Function1<String, String>() { public String apply(String s) { return s + "!!!"; } }; f.apply(”Hello, Scala");
  17. scala> { s: String => s + "!!!" }.apply("Hello, Scala")

    res1: String = Hello, Scala!!! (s -> s + "!!!")("Hello, Scala");
  18. scala> "Hello, Scala" split ", " length <console>:8: warning: postfix

    operator length should be enabled by making the implicit value scala.language.postfixOps visible. This can be achieved by adding the import clause 'import scala.language.postfixOps'
  19. scala> ("Hello, Scala" split ", ") length <console>:8: warning: postfix

    operator length should be enabled by making the implicit value scala.language.postfixOps visible. This can be achieved by adding the import clause 'import scala.language.postfixOps'
  20. scala> Array(2, 3, 5, 8, 13, 21, 43) res0: Array[Int]

    = Array(2, 3, 5, 8, 13, 21, 43) scala> res0.map(x => x * 2) res1: Array[Int] = Array(4, 6, 10, 16, 26, 42, 86) scala> res0.filter { x => x % 2 == 0 } res2: Array[Int] = Array(2, 8) scala> res0.toList res3: List[Int] = List(2, 3, 5, 8, 13, 21, 43) COLLECTIONS
  21. scala> res3 res4: List[Int] = List(2, 3, 5, 8, 13,

    21, 43) scala> res3.map(x => x * 2) res5: List[Int] = List(4, 6, 10, 16, 26, 42, 86) scala> res3.filter { x => x % 2 == 0 } res6: List[Int] = List(2, 8) scala> res3.toSet res7: Set[Int] = Set(5, 21, 13, 2, 3, 43, 8) BATTERIES INCLUDED
  22. scala> res7 res8: Set[Int] = Set(5, 21, 13, 2, 3,

    43, 8) scala> res7.map(x => x * 2) res9: Set[Int] = Set(10, 42, 6, 86, 16, 26, 4) scala> res7.filter { x => x % 2 == 0 } res10: Set[Int] = Set(2, 8) scala> res7.toStream res11: Stream[Int] = Stream(5, ?) HECK YEA!
  23. final class Vector[+A] private[immutable] (private[collection] val startIndex: Int, private[collection] val

    endIndex: Int, focus: Int) extends AbstractSeq[A] with IndexedSeq[A] with GenericTraversableTemplate[A, Vector] with IndexedSeqLike[A, Vector[A]] with VectorPointer[A @uncheckedVariance] with Serializable with CustomParallelizable[A, ParVector[A]] sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] with Serializable { class ListMap[A, +B] extends AbstractMap[A, B] with Map[A, B] with MapLike[A, B, ListMap[A, B]] with Serializable {
  24. final def map[B](f: (A) => B): List[B] final def map[B,

    That](f: (A) => B)(implicit bf: CanBuildFrom[List[A], B, That]): That
  25. public class Person { private final String name; private final

    int age; public Person(final String name, final Integer age) { if(age == null || name == null) throw new NullPointerException(); this.name = name; this.age = age; } public String name() { return name; } public int age() { return age; } public Person copy(String name, Integer age) { return apply(name == null ? this.name : name, age == null ? this.age : age); } public Person copy(String name) { return apply(name == null ? this.name : name, this.age); } public Person copy(Integer age) { return apply(this.name, age == null ? this.age : age); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Person other = (Person) obj; if (age != other.age) { return false; } if (name == null && other.name != null) { return false; } else if (!name.equals(other.name)) { return false; } return true; } @Override public String toString() { return "Person(name=" + name + ", age=" + age + ")"; } public static Person apply(String name, int age) { return new Person(name, age); } }
  26. public class Person { private final String name; private final

    int age; public Person(final String name, final Integer age) { if(age == null || name == null) throw new NullPointerException(); this.name = name; this.age = age; } public String name() { return name; } public int age() { return age; }
  27. public Person copy(String name, Integer age) { return apply(name ==

    null ? this.name : name, age == null ? this.age : age); } public Person copy(String name) { return apply(name == null ? this.name : name, this.age); } public Person copy(Integer age) { return apply(this.name, age == null ? this.age : age); }
  28. @Override public boolean equals(Object obj) { if (this == obj)

    return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null && other.name != null) return false; else if (!name.equals(other.name)) return false; return true; }
  29. @Override public int hashCode() { final int prime = 31;

    int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public String toString() { return "Person(name=" + name + ", age=" + age + ")"; }
  30. package com.velvet.model; public class Person { private final String name;

    private final int age; public Person(final String name, final Integer age) { if(age == null || name == null) throw new NullPointerException(); this.name = name; this.age = age; } public String name() { return name; } public int age() { return age; } public Person copy(String name, Integer age) { return new Person(name == null ? this.name : name, age == null ? this.age : age); } public Person copy(String name) { return new Person(name == null ? this.name : name, this.age); } public Person copy(Integer age) { return new Person(this.name, age == null ? this.age : age); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Person other = (Person) obj; if (age != other.age) { return false; } if (name == null && other.name != null) { return false; } else if (!name.equals(other.name)) { return false; } return true; } @Override public String toString() { return "Person(name=" + name + ", age=" + age + ")"; } public static Person apply(String name, int age) { return new Person(name, age); } } case class Person(name: String, age: Int)
  31. trait Logger { val leftSep = "["; val rightSep =

    "]" protected def print(message: String) def error(message: String) = { print(s"${leftSep}error${rightSep} $message") } } TRAITS
  32. sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product

    with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] with Serializable { MULTIPLE INHERITANCE
  33. scala> new Person("dotz", 32) with ConsoleLogger res14: Person with ConsoleLogger

    = Person(dotz,32) scala> res14 error "derp" [error] derp TRAITS
  34. scala> import java.util.Calendar import java.util.Calendar scala> lazy val lazyTime =

    Calendar.getInstance.getTimeInMillis lazyTime: Long = <lazy> scala> Calendar.getInstance.getTimeInMillis res0: Long = 1431905681166 scala> lazyTime res1: Long = 1431905685466 LAZY VALS
  35. class UnixTime(val seconds: Long) object UnixTime { def now =

    new UnixTime(Calendar.getInstance.getTimeInMillis / 1000) } OBJECTS
  36. def fibonacci(n: Int):Int = {
 def fib(n: Int, curr: Int,

    acc: Int):Int =
 if (n == 0) acc
 else fib(n - 1, acc, curr + acc) 
 fib(n, 1, 0)
 } TAIL-CALL RECURSION
  37. def factorial(n:Int):Int = n match { case 0 => 1

    case _ => n * factorial(n-1) } TAIL-CALL RECURSION
  38. @tailrec def factorial(n:Int):Int = n match { case 0 =>

    1 case _ => n * factorial(n-1) } TAIL-CALL RECURSION <console>:11: error: could not optimize @tailrec annotated method factorial: it contains a recursive call not in tail position case _ => n * factorial(n-1)
  39. PATTERN MATCHING def magicNumber(n: Int) = n match { case

    3 => "IT'S THE MAGIC NUMBER!" case _ => "just an ordinary number" }
  40. scala> List(1,2,3,4) match { | case head :: tail =>

    (head, tail) | } res0: (Int, List[Int]) = (1,List(2, 3, 4)) PATTERN MATCHING
  41. scala> List(1,2,3,4) match { | case head :: tail =>

    (head, tail) | } <console>:8: warning: match may not be exhaustive. It would fail on the following input: Nil List(1,2,3,4) match { ^ res0: (Int, List[Int]) = (1,List(2, 3, 4)) PATTERN MATCHING
  42. List(1,2,3,4) match { case head :: tail => (head, tail)

    case _ => (0, None) } PATTERN MATCHING
  43. scala> List(1,2,3,4) match { | case head :: tail =>

    (head, tail) | case _ => (0, None) | } res1: (Int, Product with java.io.Serializable) = (1,List(2, 3, 4)) PATTERN MATCHING
  44. val BigFoo = "foo" "bar" match { case BigFoo =>

    "doesn't match" } PATTERN MATCHING
  45. val foo = "foo" "bar" match { case foo =>

    "this also matches! } PATTERN MATCHING val foo = "foo" "bar" match { case foo => "this also matches! } different "foo"s
  46. scala> val x = 5 x: Int = 5 scala>

    def f(implicit i: Int) = i + 5 f: (implicit i: Int)Int scala> f <console>:9: error: could not find implicit value for parameter i: Int f ^ scala> implicit val x = 5 x: Int = 5 scala> f res3: Int = 10 IMPLICIT VALUES
  47. scala> import scala.language.{postfixOps, implicitConversions, reflectiveCalls} import scala.language.{postfixOps, implicitConversions, reflectiveCalls} scala>

    implicit def makeFooable(s: String) = new Object { def isFoo = s == "foo" } makeFooable: (s: String)Object{def isFoo: Boolean} scala> "abc" isFoo res0: Boolean = false scala> "foo" isFoo res1: Boolean = true IMPLICIT FUNCTIONS
  48. scala> import scala.language.implicitConversions import scala.language.implicitConversions scala> implicit def doubleToInt(x: Double)

    = x.toInt doubleToInt: (x: Double)Int scala> val i: Int = 3.5 i: Int = 3 IMPLICIT FUNCTIONS
  49. scala> implicit class FooableString(s: String) { | def isFoo =

    s == "foo" | } defined class FooableString scala> "foo" isFoo res1: Boolean = true IMPLICIT CLASSES
  50. trait Mappable[T[_]] { def map[A,B](x: T[A])(f: A => B):T[B] }

    class Stupid[+A](val a: A) object Stupid { def apply[A](x: => A) = new Stupid[A](x) } implicit object StupidMappable extends Mappable[Stupid] { override def map[A, B](x: Stupid[A])(f: (A) => B) = new Stupid[B](f(x.a)) } implicit def makeMappableATypeClass[S[_] : Mappable, A](stupidThing: S[A]) = new { val functor = implicitly[Mappable[S]] final def map[B](f: A => B): S[B] = functor.map(stupidThing)(f) } TYPE CLASSES
  51. scala> def add(x: Int)(y: Int) = x + y add:

    (x: Int)(y: Int)Int scala> add(2) _ res0: Int => Int = <function1> scala> res0(3) res1: Int = 5 CURRYING
  52. scala> def add2(x: Int, y: Int) = x + y

    add2: (x: Int, y: Int)Int scala> (add2 _).curried res0: Int => (Int => Int) = <function1> CURRYING