// Case classes
case class Foo(s1: String, s2: String)
val foo = Foo("Hello", "World")
Foo("Hello", "World") == Foo("Hello", "World") // returns true
// Traits
trait Behavior1 { def doSomething() = /*...*/ }
trait Behavior2 { def doSomethingElse() = /*...*/ }
case class Foo extends Behavior1 with Behavior2
/* ... with BehaviorN */
// Objects
object Bar {
def newBarWithFalse = new Bar(false)
}
class Bar(val foo: Boolean)
/*...*/
Bar.newBarWithFalse // returns Bar(false)
// Common classes
class Foo(val s1: String, var s2: String = "bar")
val foo = new Foo(s1 = "Hello World")
// Case classes
case class Foo(s1: String, s2: String)
val foo = Foo("Hello", "World")
Foo("Hello", "World") == Foo("Hello", "World") // returns true
// Traits
trait Behavior1 { def doSomething() = /*...*/ }
trait Behavior2 { def doSomethingElse() = /*...*/ }
case class Foo extends Behavior1 with Behavior2
/* ... with BehaviorN */
// Objects
object Bar {
def newBarWithFalse = new Bar(false)
}
class Bar(val foo: Boolean)
/*...*/
Bar.newBarWithFalse // returns Bar(false)
// Common classes
class Foo(val s1: String, var s2: String = "bar")
val foo = new Foo(s1 = "Hello World")
// Case classes
case class Foo(s1: String, s2: String)
val foo = Foo("Hello", "World")
Foo("Hello", "World") == Foo("Hello", "World") // returns true
// Traits
trait Behavior1 { def doSomething() = /*...*/ }
trait Behavior2 { def doSomethingElse() = /*...*/ }
case class Foo extends Behavior1 with Behavior2
/* ... with BehaviorN */
// Objects
object Bar {
def newBarWithFalse = new Bar(false)
}
class Bar(val foo: Boolean)
/*...*/
Bar.newBarWithFalse // returns Bar(false)
// Common classes
class Foo(val s1: String, var s2: String = "bar")
val foo = new Foo(s1 = "Hello World")
// Case classes
case class Foo(s1: String, s2: String)
val foo = Foo("Hello", "World")
Foo("Hello", "World") == Foo("Hello", "World") // returns true
// Traits
trait Behavior1 { def doSomething() = /*...*/ }
trait Behavior2 { def doSomethingElse() = /*...*/ }
case class Foo extends Behavior1 with Behavior2
/* ... with BehaviorN */
// Objects
object Bar {
def newBarWithFalse = new Bar(false)
}
class Bar(val foo: Boolean)
/*...*/
Bar.newBarWithFalse // returns Bar(false)
// Common classes
class Foo(val s1: String, var s2: String = "bar")
val foo = new Foo(s1 = "Hello World")
Functions
def name(arg: Type,...): Returned_Type = body
def substract(x:Int, y:Int): Int = { x - y }
def printHelloWorld: Unit = println("hello world !")
def foo(): Int = {
def bar(): Int = { ... }
}
Anonymous
val name: (arg type,...) => Returned Type = body
val multiply: (Int, Int) => Int = (x,y) => x * y
def name(arg: Type,...): Returned_Type = body
def substract(x:Int, y:Int): Int = { x - y }
def printHelloWorld: Unit = println("hello world !")
def foo(): Int = {
def bar(): Int = { ... }
}
Anonymous
val name: (arg type,...) => Returned Type = body
val multiply: (Int, Int) => Int = (x,y) => x * y
def name(arg: Type,...): Returned_Type = body
def substract(x:Int, y:Int): Int = { x - y }
def printHelloWorld: Unit = println("hello world !")
def foo(): Int = {
def bar(): Int = { ... }
}
Anonymous
val name: (arg type,...) => Returned Type = body
val multiply: (Int, Int) => Int = (x,y) => x * y
Higher Order Functions
val func: (arg type,...) => Returned Type = body
val multiply: (Int, Int) => Int = (x,y) => x * y
val foo: Int => Int = x => x + 1
def bar(f: Int => Int, number: Int ): Int = f(number)
bar(foo, 41)
def bar(f: Int => Int): (Int, Int) => Int = (x, y) => f(x + y)
bar(x => x * 2)(2, 3)
Multiple-argument-list function
def reduce(combine: (Int, Int) => Int)
(x: Int, y: Int): Int = combine(x, y)
val sum: (Int, Int) => Int = reduce((x,y) => x + y)
sum(1, 2)
val func: (arg type,...) => Returned Type = body
val multiply: (Int, Int) => Int = (x,y) => x * y
val foo: Int => Int = x => x + 1
def bar(f: Int => Int, number: Int ): Int = f(number)
bar(foo, 41)
def bar(f: Int => Int): (Int, Int) => Int = (x, y) => f(x + y)
bar(x => x * 2)(2, 3)
Multiple-argument-list function
def reduce(combine: (Int, Int) => Int)
(x: Int, y: Int): Int = combine(x, y)
val sum: (Int, Int) => Int = reduce((x,y) => x + y)
sum(1, 2)
val func: (arg type,...) => Returned Type = body
val multiply: (Int, Int) => Int = (x,y) => x * y
val foo: Int => Int = x => x + 1
def bar(f: Int => Int, number: Int ): Int = f(number)
bar(foo, 41)
def bar(f: Int => Int): (Int, Int) => Int = (x, y) => f(x + y)
bar(x => x * 2)(2, 3)
Multiple-argument-list function
def reduce(combine: (Int, Int) => Int)
(x: Int, y: Int): Int = combine(x, y)
val sum: (Int, Int) => Int = reduce((x,y) => x + y)
sum(1, 2)
Type inference
val integer: Int = 1
val integer = 1
def getData = { "hello world !" }
def printHelloWorld = { println("hello world !") }
val multiply = (x:Int, y:Int) => x * y
val list = List(1,2,3)
list.filter(int => int > 1)
list.filter(_ > 1) // returns List(2,3)
def reduce(f: (Int, Int) => Int)(x:Int, y:Int) = f(x,y)
reduce((a,b) => a + b)(1, 2) // a and b's type are inferred
reduce(_ + _)(1, 2)
val integer: Int = 1
val integer = 1
def getData = { "hello world !" }
def printHelloWorld = { println("hello world !") }
val multiply = (x:Int, y:Int) => x * y
val list = List(1,2,3)
list.filter(int => int > 1)
list.filter(_ > 1)
def reduce(f: (Int, Int) => Int)(x:Int, y:Int) = f(x,y)
reduce((a,b) => a + b)(1, 2) // a and b's type are inferred
reduce(_ + _)(1, 2)
val integer: Int = 1
val integer = 1
def getData = { "hello world !" }
def printHelloWorld = { println("hello world !") }
val multiply = (x:Int, y:Int) => x * y
val list = List(1,2,3)
list.filter(int => int > 1)
list.filter(_ > 1)
def reduce(f: (Int, Int) => Int)(x:Int, y:Int) = f(x,y)
reduce((a,b) => a + b)(1, 2)
reduce(_ + _)(1, 2)
Error handling and prevention
val foo: Option[String] = Option("ok") // returns Some("ok")
val bar: Option[String] = Option(null) // returns None
val foo: Try[String] = Try { /* exception */ } // returns Failure(ex)
val bar: Try[String] = Try { "ok" } // returns Success("ok")
val optionX = Option(42) // Some(42)
optionX.filter(_ > 45) // None
optionX.filter(_ > 40) // Some(42)
val dangerousInt = Try(1/0) // Failure(java.lang.ArithmeticException)
dangerousInt.map(_ + 42) // Failure(java.lang.ArithmeticException)
dangerousInt.getOrElse(-1)
dangerousInt.get // throws an exception if equal to None or Failure
val foo: Option[String] = Option("ok") // returns Some("ok")
val bar: Option[String] = Option(null) // returns None
val foo: Try[String] = Try { /* exception */ } // returns Failure(ex)
val bar: Try[String] = Try { "ok" } // returns Success("ok")
val optionX = Option(42) // Some(42)
optionX.filter(_ > 45) // None
optionX.filter(_ > 40) // Some(42)
val dangerousInt = Try(1/0) // Failure(java.lang.ArithmeticException)
dangerousInt.map(_ + 42) // Failure(java.lang.ArithmeticException)
dangerousInt.getOrElse(-1)
dangerousInt.get // throws an exception if equal to None or Failure
val foo: Option[String] = Option("ok") // returns Some("ok")
val bar: Option[String] = Option(null) // returns None
val foo: Try[String] = Try { /* exception */ } // returns Failure(ex)
val bar: Try[String] = Try { "ok" } // returns Success("ok")
val optionX = Option(42)
optionX.filter(_ > 45) // None
optionX.filter(_ > 40) // Some(42)
val dangerousInt = Try(1/0)
dangerousInt.map(_ + 42) // Failure(java.lang.ArithmeticException)
dangerousInt.getOrElse(-1)
dangerousInt.get // throws an exception if equal to None or Failure
val foo: Option[String] = Option("ok") // returns Some("ok")
val bar: Option[String] = Option(null) // returns None
val foo: Try[String] = Try { /* exception */ } // returns Failure(ex)
val bar: Try[String] = Try { "ok" } // returns Success("ok")
val optionX = Option(42)
optionX.filter(_ > 45) // None
optionX.filter(_ > 40) // Some(42)
val dangerousInt = Try(1/0)
dangerousInt.map(_ + 42) // Failure(java.lang.ArithmeticException)
dangerousInt.getOrElse(-1) // Returns -1 if value cannot be found
dangerousInt.get // throws an exception if equal to None or Failure
val foo: Option[String] = Option("ok") // returns Some("ok")
val bar: Option[String] = Option(null) // returns None
val foo: Try[String] = Try { /* exception */ } // returns Failure(ex)
val bar: Try[String] = Try { "ok" } // returns Success("ok")
val optionX = Option(42)
optionX.filter(_ > 45) // None
optionX.filter(_ > 40) // Some(42)
val dangerousInt = Try(1/0)
dangerousInt.map(_ + 42) // Failure(java.lang.ArithmeticException)
dangerousInt.getOrElse(-1) // Returns -1 if value cannot be found
dangerousInt.get // throws an exception if equal to None or Failure
Pattern Matching
e match {
case pattern [guard] => case_block
case _ =>
}
case class Foo(s: String, i: Int)
Foo("Hello Confoo", 10) match {
case Foo(_, i) if integer > 0 => print("Foo with positive i")
case Foo(s, _) => print("Foo with non-positive i")
case _ => println("foo is not a Foo")
}
e match {
case head :: tail => println("this is a list !")
case (x, y) => println(s"this is a tuple with values $x and $y !")
case Some(value) => println(s"this is an option containing $value")
}
e match {
case pattern [guard] => case_block
case _ =>
}
case class Foo(s: String, i: Int)
Foo("Hello Confoo", 10) match {
case Foo(_, i) if integer > 0 => print("Foo with positive i")
case Foo(s, _) => print("Foo with non-positive i")
case _ => println("foo is not a Foo")
}
e match {
case head :: tail => println("this is a list !")
case (x, y) => println(s"this is a tuple with values $x and $y !")
case Some(value) => println(s"this is an option containing $value")
}
e match {
case pattern [guard] => case_block
case _ =>
}
case class Foo(s: String, i: Int)
Foo("Hello Confoo", 10) match {
case Foo(_, i) if integer > 0 => print("Foo with positive i")
case Foo(s, _) => print("Foo with non-positive i")
case _ => println("foo is not a Foo")
}
e match {
case head :: tail => println("this is a list !")
case (x, y) => println(s"this is a tuple with values $x and $y !")
case Some(value) => println(s"this is an option containing $value")
}
Implicits
case class Foo(string: String)
def bar()(implicit foo: Foo) = println(foo.string)
implicit val implicitFoo = Foo("Hello Confoo")
bar() // prints "Hello Confoo"
object Foo { implicit val defaultFoo = Foo("Default message") }
bar() // prints "Default message"
// Type conversion
case class Foo(s: String)
implicit def fooToInt(foo:Foo): Int = foo.s.toInt
val i: Int = Foo("42") // returns 42
// Class extension
implicit case class RichInt(int: Int) {
def doSomething() = /*...*/
}
/*...*/
42.doSomething()
package object v1 { implicit val v1Foo = Foo("Foo v1") }
package object v2 { implicit val v2Foo = Foo("Foo v2") }
// ...
def run(v1IsEnabled:Boolean): Unit = {
if(v1IsEnabled) { import v1._; bar() }
else { import v2._; bar() }
}
def compare[A](x: A, y: A)(implicit order: Ordering[A]) = order.compare(x, y)
def compare[A : Ordering](x: A, y: A) = implicitly[Ordering[A]].compare(x, y)
trait TraversableOnce[+A] {
def toMap[T, U](implicit ev: <:< [A, (T, U)]): immutable.Map[T, U]
}
def compare[A](x: A, y: A)(implicit order: Ordering[A]) = order.compare(x, y)
def compare[A : Ordering](x: A, y: A) = implicitly[Ordering[A]].compare(x, y)
trait TraversableOnce[+A] {
def toMap[T, U](implicit ev: <:< [A, (T, U)]): immutable.Map[T, U]
}
def print[T](value: T): Unit
def print[T](value: T): Unit = value match {
case s:String => println(s"This is a string %value")
case i:Int => println(s"This is an Int %value")
/*...*/
}
trait Printer[T] { def print(value: T): Unit }
def print[T: Printer](value: T): Unit = implicitly[Printer[T]].print(value)
object Printer {
implicit object StringPrinter extends Printer[String] {
def print(string: String): Unit = println(s"This is a string %string")
}
implicit object IntPrinter extends Printer[Int] {
def print(int: Int): Unit = println(s"This is an Int %int")
}
/*...*/
}
trait Printer[T] { def print(value: T): Unit }
def print[T: Printer](value: T): Unit = implicitly[Printer[T]].print(value)
object Printer {
implicit object StringPrinter extends Printer[String] {
def print(string: String): Unit = println(s"This is a string %string")
}
implicit object IntPrinter extends Printer[Int] {
def print(int: Int): Unit = println(s"This is an Int %int")
}
/*...*/
}
- Boilerplate code reduction
- Transparent adapters and decorators
- New Behaviors Introduction (Type classes)
Stackable Trait Pattern
class IntQueue(ints: List[Int] = List.empty) {
def push(int: Int) = new IntQueue(int :: ints)
}
class PositiveIntQueue extends IntQueue {
override def push(int: Int) = if(int > 0) super.push(int) else this
}
class DoubledIntQueue extends IntQueue {
override def push(int: Int) = super.push(int * 2)
}
class IntQueue(ints: List[Int] = List.empty) {
def push(int: Int) = new IntQueue(int :: ints)
}
class PositiveIntQueue extends IntQueue {
override def push(int: Int) = if(int > 0) super.push(int) else this
}
class DoubledIntQueue extends IntQueue {
override def push(int: Int) = super.push(int * 2)
}
trait Doubling extends IntQueue {
override def push(int: Int) = super.push(int * 2)
}
trait Incrementing extends IntQueue {
override def push(int: Int) = super.push(int + 1)
}
trait Filtering extends IntQueue {
override def push(int: Int) = if(int > 0) super.push(int) else this
}
val queue = new IntQueue with Doubling with Incrementing with Filtering
queue.push(1).push(2).push(0) // returns IntQueue(6, 4)
val queue = new IntQueue with Doubling with Filtering with Incrementing
queue.push(1).push(2).push(0) // returns IntQueue(4, 6, 4)