KEMBAR78
So various polymorphism in Scala | PDF
SO VARIOUS
POLYMORPHISM
IN SCALA
Boris Trofimov
@ Sigma Software
@b0ris_1
AGENDA
WHY
SCALA
CONTEXT
MAP
POLYMORPHISM
DEFINITION
BASIC
DEGREE
BACHELOR
DEGREE
MAST
DEGR
Why Scala?
Context Map
Polymorphism Definition
Basic Degree
Bachelor degree
Master degree
Ph.D
DO YOU ACCEPT
SAPIR–WHORF
HYPOTHESIS?
WHY
SCALA
CONTEXT
MAP
POLYMORPHISM
DEFINITION
BASIC
DEGREE
BACHELOR
DEGREE
MAST
DEGR
WHY
SCALA
AGENDA
WHY
SCALA
CONTEXT
MAP
POLYMORPHISM
DEFINITION
BASIC
DEGREE
BACHELOR
DEGREE
MAST
DEGR
AGENDA
 Object-Oriented Meets Functional
 Strongly Functional
 It makes you love your code again
 Scalable grammar
 Hello Domain Specific Languages (DSL)
 Inexhaustible language for every day
SCALA JAVA
class A (p: String) class A {
final String p;
public A(String p) {
this.p = p;
}
}
val variable = "string" final String variable = "string" ;
def func (p: String): String = {...} String func (String p) { ... }
trait A { def run() } interface A {
void run() ;
}
сlass A[B <: C] { … } class A <B extends C> { ... }
object A { … } Class - Singleton definition
CONTEXT
MAP
POLYMORPHISM
DEFINITION
BASIC
DEGREE
BACHELOR
DEGREE
MAST
DEGR
CONTEXT
MAP
WHY
SCALA
AGENDA
CONTEXT
MAP
POLYMORPHISM
DEFINITION
BASIC
DEGREE
BACHELOR
DEGREE
MAST
DEGR
POLYMORPHISM
DEFINITION
WHY
SCALA
AGENDA
 Ability of language to handle data of different types in the same way.
 Provision of a single interface to entities of different types.
 Particular code is able to handle data of different types.
 Way to change code behavior via input parameters without direct
modification (respecting Open-Closed Principle)
Polymorphic code will be
highlighted in a frame
BASIC
DEGREE
AD-HOC SUBTYPING
PARAMETRIC
POLYMORPHISM
REFLECTION
SUBTYPING
FUNCTIONAL
SUBTYPING
abstract class A{
def method() {
...
this.doSomething
...
}
// abstract method
def doSomething
}
class B extends A{
override def doSomething { … }
}
class B extends C{
override def doSomething { … }
}
AD-HOC SUBTYPING
PARAMETRIC
POLYMORPHISM
REFLECTION
SUBTYPING
FUNCTIONAL
SUBTYPING
trait A
class B extends A
class C extends A
class List {
def add(a : A) = {
...
}
}
SUBTYPINGAD-HOC
AD-HOC SUBTYPING
PARAMETRIC
POLYMORPHISM
REFLECTION
SUBTYPING
FUNCTIONAL
SUBTYPING
AD-HOC
class MyClass {
def addItem[A](a: A): List[A] = {
val list = new ListBuffer[A]
list += a
list.toList()
}
// B should be inheritor of ParentClass
def addItem[B <: ParentClass] (b: B) : List[A] = {
val list = new ListBuffer[B]
list += b
list.toList()
}
}
PARAMETRIC
POLYMORPHISM
AD-HOC SUBTYPING
PARAMETRIC
POLYMORPHISM
REFLECTION
SUBTYPING
FUNCTIONAL
SUBTYPING
AD-HOC
REFLECTION
SUBTYPING
class MyClass {
def doSomething(a: Object) = {
...
val method = a.getClass().getMethod("run", Int)
method.invoke(a, 1)
...
}
}
AD-HOC SUBTYPING
PARAMETRIC
POLYMORPHISM
REFLECTION
SUBTYPING
FUNCTIONAL
SUBTYPING
AD-HOC
FUNCTIONAL
SUBTYPING
class List[A] {
...
def sort(data : (A, A) => Int ) : List[A] = {
...
}
}
object Application extends App{
val list = List(7,8,5,4)
list.sort( (a,b) => a – b ) // _-_
}
BACHELOR
DEGREE
DUCK
SUBTYPING
CAKE
PATTERN
CHAINING
POLYMORPHISM
When I see a bird that walks like a duck and swims like a duck and quacks
like a duck, I call that bird a duck
class MyClass {
def doSomething(a : type { def run(i : Int) } ) = {
...
a.run(1)
...
}
}
class DuckClass {
def run(i : Int) {
...
}
}
new MyClass().doSomething( new DuckClass() )
Caution: Reflection!
CAKE
PATTERN
CHAINING
POLYMORPHISM
DUCK
SUBTIPING
CAKE
PATTERN
trait ComponentA {
def doThis() : String
}
trait ComponentB {
def doThat() : String
}
class OurComponent extends ComponentA with ComponentB {
def doSomething() = doThis() + doThat()
}
CAKE
PATTERN
CHAINING
POLYMORPHISM
DUCK
SUBTIPING
CAKE
PATTERN
trait ComponentA {
def doThis() : String
}
trait ComponentB {
def doThat() : String
}
class OurComponent extends ComponentA with ComponentB {
def doSomething() = doThis() + doThat()
}
trait ComponentAImpl extends ComponentA {
def doThis() = "hello Component A"
}
trait ComponentBImpl extends ComponentB {
def doThat() = "hello Component B"
}
CAKE
PATTERN
CHAINING
POLYMORPHISM
DUCK
SUBTIPING
CAKE
PATTERN
trait ComponentA {
def doThis() : String
}
trait ComponentB {
def doThat() : String
}
class OurComponent extends ComponentA with ComponentB {
def doSomething() = doThis() + doThat()
}
trait ComponentAImpl extends ComponentA {
def doThis() = "hello Component A"
}
trait ComponentBImpl extends ComponentB {
def doThat() = "hello Component B"
}
object Main extends App{
val obj = new OurComponent with ComponentAImpl with ComponentBImpl
println( obj.doSomething() )
}
CAKE
PATTERN
CHAINING
POLYMORPHISM
DUCK
SUBTIPING
CHAINING
POLYMORPHISM
trait AbstractOperation { def run() }
class SaveToDataBaseOperation extends AbstractOperation {
override def run(): Unit = {
println("Save it to database")
}
}
CAKE
PATTERN
CHAINING
POLYMORPHISM
DUCK
SUBTIPING
CHAINING
POLYMORPHISM
trait AbstractOperation { def run() }
class SaveToDataBaseOperation extends AbstractOperation {
override def run(): Unit = {
println("Save it to database")
}
}
// decorating with audit
trait AuditDecorator extends AbstractOperation {
abstract override def run(): Unit = {
println("Entering AuditDecorator")
super.run()
println("Leaving AuditDecorator")
}
}
// decorating with caching
trait CachingDecorator extends AbstractOperation {
abstract override def run(): Unit = {
println("Caching something")
super.run()
}
}
CAKE
PATTERN
CHAINING
POLYMORPHISM
DUCK
SUBTIPING
CHAINING
POLYMORPHISM
trait AbstractOperation { def run() }
class SaveToDataBaseOperation extends AbstractOperation {
override def run(): Unit = {
println("Save it to database")
}
}
// decorating with audit
trait AuditDecorator extends AbstractOperation {
abstract override def run(): Unit = {
println("Entering AuditDecorator")
super.run()
println("Leaving AuditDecorator")
}
}
// decorating with caching
trait CachingDecorator extends AbstractOperation {
abstract override def run(): Unit = {
println("Caching something")
super.run()
}
}
object MyApp extends App {
val operation =
new SaveToDataBaseOperation with CachingDecorator with AuditDecorator
operation.run()
}
OUTPUT:
>Entering AuditDecorator
>Caching something
>Save it to database
>Leaving AuditDecorator
MASTER
DEGREE
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
object Test{
println( Arithmetics.add("Hello", " World") ) // returns “Hello World”
println( Arithmetics.add(2,3) ) // returns 5
// Compile Error, could not find corresponding implicit object
println( Arithmetics.add(123.0, -45.345) )
}
F-BOUNDED
POLYMORPHISM
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
object Test{
println( Arithmetics.add("Hello", " World") ) // returns “Hello World”
println( Arithmetics.add(2,3) ) // returns 5
// Compile Error, could not find corresponding implicit object
println( Arithmetics.add(123.0, -45.345) )
}
trait NumericLike[T] {
def plus(x : T, y: T) : T
}
implicit object TInteger extends NumericLike[Int]{
def plus(x : Int, y: Int) : Int = x + y
}
implicit object TString extends NumericLike[String]{
def plus(x : String, y: String) : String = x + y
}
object Arithmetics{
// generalized `add` method
def add[T : NumericLike](x:T, y:T): T = {
val engine = implicitly[NumericLike[T]]
engine.plus(x, y)
}
}
Type Class Pattern
F-BOUNDED
POLYMORPHISM
Type Class can be
treated as an advocate
for specific type T
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
RETROACTIVE
POLYMORPHISM
TYPE CLASSES
https://github.com/spray/spray-json
import spray.json._
import DefaultJsonProtocol._
// from json
val source = """{ "some": ["JSON source"] }"""
val ast = source.parseJson
val myObject = ast.convertTo[Map[String, Array[String]]]
// to json
val jsonAst = Map(Array("1"), Array("1")).toJson // to ast
val json = jsonAst.prettyPrint // or .compactPrint
class Color(val name: String, val red: Int, val green: Int, val blue: Int)
// custom serializer via type class
object MyJsonProtocol extends DefaultJsonProtocol {
implicit object ColorJsonFormat extends RootJsonFormat[Color] {
def write(c: Color) = . . .
def read(value: JsValue) = ...
}
}
import MyJsonProtocol._
val json = Color("CadetBlue", 95, 158, 160).toJson
val color = json.convertTo[Color]
The ability to extend functionality of a library without modifying its source is known
as Retroactive Extension
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
IMPLICIT DI
RETROACTIVE
POLYMORPHISM
trait Future[+T] extends Awaitable[T] {
…
def filter(pred: T => Boolean) (implicit executor: ExecutionContext):
Future[T] =
map {
r => if (pred(r)) r else throw new
NoSuchElementException("Future.filter predicate is not satisfied")
}
def map[S](f: T => S) (implicit executor: ExecutionContext): Future[S] = {
// transform(f, identity)
val p = Promise[S]()
onComplete { v => p complete (v map f) }
p.future
}
}
TYPE CLASSES
Dependency Injection per
method
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
IMPLICIT DI
RETROACTIVE
POLYMORPHISM
trait Future[+T] extends Awaitable[T] {
…
def filter(pred: T => Boolean) (implicit executor: ExecutionContext):
Future[T] =
map {
r => if (pred(r)) r else throw new
NoSuchElementException("Future.filter predicate is not satisfied")
}
def map[S](f: T => S) (implicit executor: ExecutionContext): Future[S] = {
// transform(f, identity)
val p = Promise[S]()
onComplete { v => p complete (v map f) }
p.future
}
}
...
import scala.concurrent.ExecutionContext.Implicits.global
val future = Future { 12345 }. map { x => x + 1} // _ + 1
TYPE CLASSES
Dependency Injection per
method
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
IMPLICIT DI
RETROACTIVE
POLYMORPHISM
trait Future[+T] extends Awaitable[T] {
…
def filter(pred: T => Boolean) (implicit executor: ExecutionContext):
Future[T] =
map {
r => if (pred(r)) r else throw new
NoSuchElementException("Future.filter predicate is not satisfied")
}
def map[S](f: T => S) (implicit executor: ExecutionContext): Future[S] = {
// transform(f, identity)
val p = Promise[S]()
onComplete { v => p complete (v map f) }
p.future
}
}
...
import scala.concurrent.ExecutionContext.Implicits.global
val future = Future { 12345 }. map { x => x + 1} // _ + 1
// test code
implicit val executionContext = mock[ExecutionContext]
val future = Future { 12345 }. map { _ + 1}
TYPE CLASSES
Dependency Injection per
method
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
TYPE
CONSTRUCTORS
TYPE CLASSES
More about motivation and examples
http://adriaanm.github.io/files/higher.pdf
Way to build generalized
types to take generics as
a parameter
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
TYPE
CONSTRUCTORS
TYPE CLASSES
object Test{
Operations.tupleize(Some(1), Some(2)) // returns Some( (1,2) )
Operations.tupleize(List(1,3), List (2,4)) //returns List( (1,2) , (3,4) )
}
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
TYPE
CONSTRUCTORS
TYPE CLASSES
object Test{
Operations.tupleize(Some(1), Some(2)) // returns Some( (1,2) )
Operations.tupleize(List(1,3), List (2,4)) //returns List( (1,2) , (3,4) )
}
trait ContainerHandler[M[_]] {
def put[A](x: A): M[A]
def get[A](m: M[A]): A
}
object Operations{
def tupleize[M[_]: ContainerHandler, A, B](fst: M[A], snd: M[B]) = {
val engine = implicitly[ContainerHandler[M]]
engine.put( Pair(engine.get(fst), engine.get(snd)) )
}
}
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
TYPE
CONSTRUCTORS
TYPE CLASSES
object Test{
Operations.tupleize(Some(1), Some(2)) // returns Some( (1,2) )
Operations.tupleize(List(1,3), List (2,4)) //returns List( (1,2) , (3,4) )
}
trait ContainerHandler[M[_]] {
def put[A](x: A): M[A]
def get[A](m: M[A]): A
}
object Operations{
def tupleize[M[_]: ContainerHandler, A, B](fst: M[A], snd: M[B]) = {
val engine = implicitly[ContainerHandler[M]]
engine.put( Pair(engine.get(fst), engine.get(snd)) )
}
}
implicit val listHandler =
new ContainerHandler[List]{ def put[A](x: A) = List(x); def get[A](m: List[A]) = m.head
}
implicit val optionHandler =
new ContainerHandler[Some]{ def put[A](x: A) = Some(x); def get[A](m: Some[A]) = m.get
}
trait Account[T <: Account[T] ] {
def addFunds(amount: BigDecimal): T
}
class CheckingAccount(total: BigDecimal, trxMaxCount: Int)
extends Account[CheckingAccount] {
def addFunds(amount: BigDecimal) : CheckingAccount =
new CheckingAccount(total + amount, trxMaxCount)
}
class SavingAccount(total: BigDecimal) extends Account[SavingAccount] {
def addFunds(amount: BigDecimal) : SavingAccount =
new SavingAccount(total + amount)
}
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
F-BOUNDED
POLYMORPHISM
TYPE CLASSES
How to define function that, though defined in terms of a supertype, will when
passed a value of some subtype will always return a value of the same subtype as
its argument?
trait Account {
def addFunds(amount: BigDecimal): Account //???
}
trait Account[T <: Account[T] ] {
def addFunds(amount: BigDecimal): T
}
class CheckingAccount(total: BigDecimal, trxMaxCount: Int)
extends Account[CheckingAccount] {
def addFunds(amount: BigDecimal) : CheckingAccount =
new CheckingAccount(total + amount, trxMaxCount)
}
class SavingAccount(total: BigDecimal) extends Account[SavingAccount] {
def addFunds(amount: BigDecimal) : SavingAccount =
new SavingAccount(total + amount)
}
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
F-BOUNDED
POLYMORPHISM
TYPE CLASSES
How to define function that, though defined in terms of a supertype, will when
passed a value of some subtype will always return a value of the same subtype as
its argument?
trait Account {
def addFunds(amount: BigDecimal): Account //???
}
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
F-BOUNDED
POLYMORPHISM
TYPE CLASSES
object Account {
val feePercentage = BigDecimal("0.02")
val feeThreshold = BigDecimal("10000.00")
def deposit[T <: Account[T]](amount: BigDecimal, account: T): T = {
if (amount < feeThreshold) account.addFunds(amount - (amount * feePercentage))
else account.addFunds(amount)
}
http://logji.blogspot.com/2012/11/f-bounded-type-polymorphism-give-up-now.html
TYPE CLASSES
RETROACTIVE
POLYMORPHISM
IMPLICIT DI
TYPE
CONSTRUCTORS
F-BOUNDED
POLYMORPHISM
F-BOUNDED
POLYMORPHISM
TYPE CLASSES
object Account {
val feePercentage = BigDecimal("0.02")
val feeThreshold = BigDecimal("10000.00")
def deposit[T <: Account[T]](amount: BigDecimal, account: T): T = {
if (amount < feeThreshold) account.addFunds(amount - (amount * feePercentage))
else account.addFunds(amount)
}
def debitAll(amount: BigDecimal, accounts: List[T forSome { type T <: Account[T] }]):
List[T forSome { type T <: Account[T] }] = {
accounts map { _.addFunds(-amount) }
}
}
object Test {
val list = List[T forSome { type T <: Account[T] }](
new CheckingAccount(BigDecimal("0"), 10),
new SavingAccount(BigDecimal("0")))
Account.debitAll(BigDecimal("10.00"), list)
}
The second frame uses
trick with existential
types to store in one
collection
http://logji.blogspot.com/2012/11/f-bounded-type-polymorphism-give-up-now.html
Scala Puzzle
def gen2(i: Int): Stream[Int] = Stream(i) append gen2(i+1)
println(gen2(0).take(10).to[List])
// > List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
def gen(i: Int): Stream[Int] = Stream(i) ++ gen(i+1)
println(gen(0).take(10).to[List])
// > List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
(2) The first fails, the second
succeeds
(1) Both will fail with
StackOverflowError
(4) The second fails, the first
succeeds
(3) Both will succeed
1
2
Ph.D
DEGREE
TYPE CLASSES
POLYMORPHIC
FUNCTIONS
RETROACTIVE
POLYMORPHISM
We treat type aliases like
abstract virtual functions
passing and returning types, for
instance:
def Prev : Nat
def Plus(A: Nat) : Nat
VIRTUAL TYPES
object Factorial extends App {
trait Nat {
type Prev <: Nat
type Plus[A <: Nat] <: Nat
type Times[A <: Nat] <: Nat
type Factorial <: Nat
}
trait _0 extends Nat {
type Prev = _0
type Plus[A <: Nat] = A
type Times[A <: Nat] = _0
type Factorial = _1
}
trait Succ[N <: Nat] extends Nat {
type This = Succ[N]
type Prev = N
type Times[A <: Nat] = A#Plus[N#Times[A]]
type Plus[A <: Nat] = N#Plus[Succ[A]]
type Factorial = This#Times[Prev#Factorial]
}
type _1 = Succ[_0]
type _2 = Succ[_1]
type _3 = Succ[_2]
type _4 = Succ[_3]
type _5 = Succ[_4]
type _6 = Succ[_5]
type _7 = Succ[_6]
type _8 = Succ[_7]
type _9 = Succ[_8]
// Calculate 3! = 6
implicitly[_3#Factorial =:= _6]
}
https://gist.github.com/mkleen/9290750
TYPE CLASSES
POLYMORPHIC
FUNCTIONS
VIRTUAL TYPES
POLYMORPHIC
FUNCTIONS
https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0
 Scala function values are monomorphic due to interface Function1[U,V] { .. }
 Shapeless library allows to avoid this limitation
 Polymorphic functions allow to process heterogeneous collections (HLists)
import poly._
// choose is a function from Sets to Options with no type specific cases
object choose extends (Set ~> Option) {
def apply[T](s : Set[T]) = s.headOption
}
scala> choose(Set(1, 2, 3))
res0: Option[Int] = Some(1)
scala> choose(Set('a', 'b', 'c'))
res1: Option[Char] = Some(a)
scala> val sets = Set(1) :: Set("foo") :: HNil
scala> val opts = sets map choose // map selects cases of choose for each HList element
opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil
Define polymorphic function
TYPE CLASSES
POLYMORPHIC
FUNCTIONS
VIRTUAL TYPES
POLYMORPHIC
FUNCTIONS
https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0
 Scala function values are monomorphic due to interface Function1[U,V] { .. }
 Shapeless library allows to avoid this limitation
 Polymorphic functions allow to process heterogeneous collections (HLists)
import poly._
// choose is a function from Sets to Options with no type specific cases
object choose extends (Set ~> Option) {
def apply[T](s : Set[T]) = s.headOption
}
scala> choose(Set(1, 2, 3))
res0: Option[Int] = Some(1)
scala> choose(Set('a', 'b', 'c'))
res1: Option[Char] = Some(a)
scala> val sets = Set(1) :: Set("foo") :: HNil
scala> val opts = sets map choose // map selects cases of choose for each HList element
opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil
It behaves like an usual function
Define polymorphic function
TYPE CLASSES
POLYMORPHIC
FUNCTIONS
VIRTUAL TYPES
POLYMORPHIC
FUNCTIONS
https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0
 Scala function values are monomorphic due to interface Function1[U,V] { .. }
 Shapeless library allows to avoid this limitation
 Polymorphic functions allow to process heterogeneous collections (HLists)
import poly._
// choose is a function from Sets to Options with no type specific cases
object choose extends (Set ~> Option) {
def apply[T](s : Set[T]) = s.headOption
}
scala> choose(Set(1, 2, 3))
res0: Option[Int] = Some(1)
scala> choose(Set('a', 'b', 'c'))
res1: Option[Char] = Some(a)
scala> val sets = Set(1) :: Set("foo") :: HNil
scala> val opts = sets map choose // map selects cases of choose for each HList element
opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil
HList runs polymorphic function
It behaves like an usual function
Define polymorphic function
REFERENCES
 http://adriaanm.github.io/files/higher.pdf
 http://twitter.github.io/scala_school/advanced-types.html
 http://logji.blogspot.com/2012/11/f-bounded-type-polymorphism-give-up-
now.html
 http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-
part-12-type-classes.html
 https://gist.github.com/mkleen/9290750
 http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-
scala/
THANK YOU

So various polymorphism in Scala

  • 1.
    SO VARIOUS POLYMORPHISM IN SCALA BorisTrofimov @ Sigma Software @b0ris_1
  • 2.
  • 3.
  • 4.
    WHY SCALA CONTEXT MAP POLYMORPHISM DEFINITION BASIC DEGREE BACHELOR DEGREE MAST DEGR AGENDA  Object-Oriented MeetsFunctional  Strongly Functional  It makes you love your code again  Scalable grammar  Hello Domain Specific Languages (DSL)  Inexhaustible language for every day
  • 5.
    SCALA JAVA class A(p: String) class A { final String p; public A(String p) { this.p = p; } } val variable = "string" final String variable = "string" ; def func (p: String): String = {...} String func (String p) { ... } trait A { def run() } interface A { void run() ; } сlass A[B <: C] { … } class A <B extends C> { ... } object A { … } Class - Singleton definition CONTEXT MAP POLYMORPHISM DEFINITION BASIC DEGREE BACHELOR DEGREE MAST DEGR CONTEXT MAP WHY SCALA AGENDA
  • 6.
    CONTEXT MAP POLYMORPHISM DEFINITION BASIC DEGREE BACHELOR DEGREE MAST DEGR POLYMORPHISM DEFINITION WHY SCALA AGENDA  Ability oflanguage to handle data of different types in the same way.  Provision of a single interface to entities of different types.  Particular code is able to handle data of different types.  Way to change code behavior via input parameters without direct modification (respecting Open-Closed Principle) Polymorphic code will be highlighted in a frame
  • 7.
  • 8.
    AD-HOC SUBTYPING PARAMETRIC POLYMORPHISM REFLECTION SUBTYPING FUNCTIONAL SUBTYPING abstract classA{ def method() { ... this.doSomething ... } // abstract method def doSomething } class B extends A{ override def doSomething { … } } class B extends C{ override def doSomething { … } }
  • 9.
    AD-HOC SUBTYPING PARAMETRIC POLYMORPHISM REFLECTION SUBTYPING FUNCTIONAL SUBTYPING trait A classB extends A class C extends A class List { def add(a : A) = { ... } } SUBTYPINGAD-HOC
  • 10.
    AD-HOC SUBTYPING PARAMETRIC POLYMORPHISM REFLECTION SUBTYPING FUNCTIONAL SUBTYPING AD-HOC class MyClass{ def addItem[A](a: A): List[A] = { val list = new ListBuffer[A] list += a list.toList() } // B should be inheritor of ParentClass def addItem[B <: ParentClass] (b: B) : List[A] = { val list = new ListBuffer[B] list += b list.toList() } } PARAMETRIC POLYMORPHISM
  • 11.
    AD-HOC SUBTYPING PARAMETRIC POLYMORPHISM REFLECTION SUBTYPING FUNCTIONAL SUBTYPING AD-HOC REFLECTION SUBTYPING class MyClass{ def doSomething(a: Object) = { ... val method = a.getClass().getMethod("run", Int) method.invoke(a, 1) ... } }
  • 12.
    AD-HOC SUBTYPING PARAMETRIC POLYMORPHISM REFLECTION SUBTYPING FUNCTIONAL SUBTYPING AD-HOC FUNCTIONAL SUBTYPING class List[A]{ ... def sort(data : (A, A) => Int ) : List[A] = { ... } } object Application extends App{ val list = List(7,8,5,4) list.sort( (a,b) => a – b ) // _-_ }
  • 13.
  • 14.
    DUCK SUBTYPING CAKE PATTERN CHAINING POLYMORPHISM When I seea bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck class MyClass { def doSomething(a : type { def run(i : Int) } ) = { ... a.run(1) ... } } class DuckClass { def run(i : Int) { ... } } new MyClass().doSomething( new DuckClass() ) Caution: Reflection!
  • 15.
    CAKE PATTERN CHAINING POLYMORPHISM DUCK SUBTIPING CAKE PATTERN trait ComponentA { defdoThis() : String } trait ComponentB { def doThat() : String } class OurComponent extends ComponentA with ComponentB { def doSomething() = doThis() + doThat() }
  • 16.
    CAKE PATTERN CHAINING POLYMORPHISM DUCK SUBTIPING CAKE PATTERN trait ComponentA { defdoThis() : String } trait ComponentB { def doThat() : String } class OurComponent extends ComponentA with ComponentB { def doSomething() = doThis() + doThat() } trait ComponentAImpl extends ComponentA { def doThis() = "hello Component A" } trait ComponentBImpl extends ComponentB { def doThat() = "hello Component B" }
  • 17.
    CAKE PATTERN CHAINING POLYMORPHISM DUCK SUBTIPING CAKE PATTERN trait ComponentA { defdoThis() : String } trait ComponentB { def doThat() : String } class OurComponent extends ComponentA with ComponentB { def doSomething() = doThis() + doThat() } trait ComponentAImpl extends ComponentA { def doThis() = "hello Component A" } trait ComponentBImpl extends ComponentB { def doThat() = "hello Component B" } object Main extends App{ val obj = new OurComponent with ComponentAImpl with ComponentBImpl println( obj.doSomething() ) }
  • 18.
    CAKE PATTERN CHAINING POLYMORPHISM DUCK SUBTIPING CHAINING POLYMORPHISM trait AbstractOperation {def run() } class SaveToDataBaseOperation extends AbstractOperation { override def run(): Unit = { println("Save it to database") } }
  • 19.
    CAKE PATTERN CHAINING POLYMORPHISM DUCK SUBTIPING CHAINING POLYMORPHISM trait AbstractOperation {def run() } class SaveToDataBaseOperation extends AbstractOperation { override def run(): Unit = { println("Save it to database") } } // decorating with audit trait AuditDecorator extends AbstractOperation { abstract override def run(): Unit = { println("Entering AuditDecorator") super.run() println("Leaving AuditDecorator") } } // decorating with caching trait CachingDecorator extends AbstractOperation { abstract override def run(): Unit = { println("Caching something") super.run() } }
  • 20.
    CAKE PATTERN CHAINING POLYMORPHISM DUCK SUBTIPING CHAINING POLYMORPHISM trait AbstractOperation {def run() } class SaveToDataBaseOperation extends AbstractOperation { override def run(): Unit = { println("Save it to database") } } // decorating with audit trait AuditDecorator extends AbstractOperation { abstract override def run(): Unit = { println("Entering AuditDecorator") super.run() println("Leaving AuditDecorator") } } // decorating with caching trait CachingDecorator extends AbstractOperation { abstract override def run(): Unit = { println("Caching something") super.run() } } object MyApp extends App { val operation = new SaveToDataBaseOperation with CachingDecorator with AuditDecorator operation.run() } OUTPUT: >Entering AuditDecorator >Caching something >Save it to database >Leaving AuditDecorator
  • 21.
  • 22.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS objectTest{ println( Arithmetics.add("Hello", " World") ) // returns “Hello World” println( Arithmetics.add(2,3) ) // returns 5 // Compile Error, could not find corresponding implicit object println( Arithmetics.add(123.0, -45.345) ) } F-BOUNDED POLYMORPHISM
  • 23.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS objectTest{ println( Arithmetics.add("Hello", " World") ) // returns “Hello World” println( Arithmetics.add(2,3) ) // returns 5 // Compile Error, could not find corresponding implicit object println( Arithmetics.add(123.0, -45.345) ) } trait NumericLike[T] { def plus(x : T, y: T) : T } implicit object TInteger extends NumericLike[Int]{ def plus(x : Int, y: Int) : Int = x + y } implicit object TString extends NumericLike[String]{ def plus(x : String, y: String) : String = x + y } object Arithmetics{ // generalized `add` method def add[T : NumericLike](x:T, y:T): T = { val engine = implicitly[NumericLike[T]] engine.plus(x, y) } } Type Class Pattern F-BOUNDED POLYMORPHISM Type Class can be treated as an advocate for specific type T
  • 24.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM RETROACTIVE POLYMORPHISM TYPECLASSES https://github.com/spray/spray-json import spray.json._ import DefaultJsonProtocol._ // from json val source = """{ "some": ["JSON source"] }""" val ast = source.parseJson val myObject = ast.convertTo[Map[String, Array[String]]] // to json val jsonAst = Map(Array("1"), Array("1")).toJson // to ast val json = jsonAst.prettyPrint // or .compactPrint class Color(val name: String, val red: Int, val green: Int, val blue: Int) // custom serializer via type class object MyJsonProtocol extends DefaultJsonProtocol { implicit object ColorJsonFormat extends RootJsonFormat[Color] { def write(c: Color) = . . . def read(value: JsValue) = ... } } import MyJsonProtocol._ val json = Color("CadetBlue", 95, 158, 160).toJson val color = json.convertTo[Color] The ability to extend functionality of a library without modifying its source is known as Retroactive Extension
  • 25.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM IMPLICITDI RETROACTIVE POLYMORPHISM trait Future[+T] extends Awaitable[T] { … def filter(pred: T => Boolean) (implicit executor: ExecutionContext): Future[T] = map { r => if (pred(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") } def map[S](f: T => S) (implicit executor: ExecutionContext): Future[S] = { // transform(f, identity) val p = Promise[S]() onComplete { v => p complete (v map f) } p.future } } TYPE CLASSES Dependency Injection per method
  • 26.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM IMPLICITDI RETROACTIVE POLYMORPHISM trait Future[+T] extends Awaitable[T] { … def filter(pred: T => Boolean) (implicit executor: ExecutionContext): Future[T] = map { r => if (pred(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") } def map[S](f: T => S) (implicit executor: ExecutionContext): Future[S] = { // transform(f, identity) val p = Promise[S]() onComplete { v => p complete (v map f) } p.future } } ... import scala.concurrent.ExecutionContext.Implicits.global val future = Future { 12345 }. map { x => x + 1} // _ + 1 TYPE CLASSES Dependency Injection per method
  • 27.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM IMPLICITDI RETROACTIVE POLYMORPHISM trait Future[+T] extends Awaitable[T] { … def filter(pred: T => Boolean) (implicit executor: ExecutionContext): Future[T] = map { r => if (pred(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") } def map[S](f: T => S) (implicit executor: ExecutionContext): Future[S] = { // transform(f, identity) val p = Promise[S]() onComplete { v => p complete (v map f) } p.future } } ... import scala.concurrent.ExecutionContext.Implicits.global val future = Future { 12345 }. map { x => x + 1} // _ + 1 // test code implicit val executionContext = mock[ExecutionContext] val future = Future { 12345 }. map { _ + 1} TYPE CLASSES Dependency Injection per method
  • 28.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM TYPE CONSTRUCTORS TYPECLASSES More about motivation and examples http://adriaanm.github.io/files/higher.pdf Way to build generalized types to take generics as a parameter
  • 29.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM TYPE CONSTRUCTORS TYPECLASSES object Test{ Operations.tupleize(Some(1), Some(2)) // returns Some( (1,2) ) Operations.tupleize(List(1,3), List (2,4)) //returns List( (1,2) , (3,4) ) }
  • 30.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM TYPE CONSTRUCTORS TYPECLASSES object Test{ Operations.tupleize(Some(1), Some(2)) // returns Some( (1,2) ) Operations.tupleize(List(1,3), List (2,4)) //returns List( (1,2) , (3,4) ) } trait ContainerHandler[M[_]] { def put[A](x: A): M[A] def get[A](m: M[A]): A } object Operations{ def tupleize[M[_]: ContainerHandler, A, B](fst: M[A], snd: M[B]) = { val engine = implicitly[ContainerHandler[M]] engine.put( Pair(engine.get(fst), engine.get(snd)) ) } }
  • 31.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM TYPE CONSTRUCTORS TYPECLASSES object Test{ Operations.tupleize(Some(1), Some(2)) // returns Some( (1,2) ) Operations.tupleize(List(1,3), List (2,4)) //returns List( (1,2) , (3,4) ) } trait ContainerHandler[M[_]] { def put[A](x: A): M[A] def get[A](m: M[A]): A } object Operations{ def tupleize[M[_]: ContainerHandler, A, B](fst: M[A], snd: M[B]) = { val engine = implicitly[ContainerHandler[M]] engine.put( Pair(engine.get(fst), engine.get(snd)) ) } } implicit val listHandler = new ContainerHandler[List]{ def put[A](x: A) = List(x); def get[A](m: List[A]) = m.head } implicit val optionHandler = new ContainerHandler[Some]{ def put[A](x: A) = Some(x); def get[A](m: Some[A]) = m.get }
  • 32.
    trait Account[T <:Account[T] ] { def addFunds(amount: BigDecimal): T } class CheckingAccount(total: BigDecimal, trxMaxCount: Int) extends Account[CheckingAccount] { def addFunds(amount: BigDecimal) : CheckingAccount = new CheckingAccount(total + amount, trxMaxCount) } class SavingAccount(total: BigDecimal) extends Account[SavingAccount] { def addFunds(amount: BigDecimal) : SavingAccount = new SavingAccount(total + amount) } TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM F-BOUNDED POLYMORPHISM TYPE CLASSES How to define function that, though defined in terms of a supertype, will when passed a value of some subtype will always return a value of the same subtype as its argument? trait Account { def addFunds(amount: BigDecimal): Account //??? }
  • 33.
    trait Account[T <:Account[T] ] { def addFunds(amount: BigDecimal): T } class CheckingAccount(total: BigDecimal, trxMaxCount: Int) extends Account[CheckingAccount] { def addFunds(amount: BigDecimal) : CheckingAccount = new CheckingAccount(total + amount, trxMaxCount) } class SavingAccount(total: BigDecimal) extends Account[SavingAccount] { def addFunds(amount: BigDecimal) : SavingAccount = new SavingAccount(total + amount) } TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM F-BOUNDED POLYMORPHISM TYPE CLASSES How to define function that, though defined in terms of a supertype, will when passed a value of some subtype will always return a value of the same subtype as its argument? trait Account { def addFunds(amount: BigDecimal): Account //??? }
  • 34.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM F-BOUNDED POLYMORPHISM TYPECLASSES object Account { val feePercentage = BigDecimal("0.02") val feeThreshold = BigDecimal("10000.00") def deposit[T <: Account[T]](amount: BigDecimal, account: T): T = { if (amount < feeThreshold) account.addFunds(amount - (amount * feePercentage)) else account.addFunds(amount) } http://logji.blogspot.com/2012/11/f-bounded-type-polymorphism-give-up-now.html
  • 35.
    TYPE CLASSES RETROACTIVE POLYMORPHISM IMPLICIT DI TYPE CONSTRUCTORS F-BOUNDED POLYMORPHISM F-BOUNDED POLYMORPHISM TYPECLASSES object Account { val feePercentage = BigDecimal("0.02") val feeThreshold = BigDecimal("10000.00") def deposit[T <: Account[T]](amount: BigDecimal, account: T): T = { if (amount < feeThreshold) account.addFunds(amount - (amount * feePercentage)) else account.addFunds(amount) } def debitAll(amount: BigDecimal, accounts: List[T forSome { type T <: Account[T] }]): List[T forSome { type T <: Account[T] }] = { accounts map { _.addFunds(-amount) } } } object Test { val list = List[T forSome { type T <: Account[T] }]( new CheckingAccount(BigDecimal("0"), 10), new SavingAccount(BigDecimal("0"))) Account.debitAll(BigDecimal("10.00"), list) } The second frame uses trick with existential types to store in one collection http://logji.blogspot.com/2012/11/f-bounded-type-polymorphism-give-up-now.html
  • 36.
    Scala Puzzle def gen2(i:Int): Stream[Int] = Stream(i) append gen2(i+1) println(gen2(0).take(10).to[List]) // > List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) def gen(i: Int): Stream[Int] = Stream(i) ++ gen(i+1) println(gen(0).take(10).to[List]) // > List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) (2) The first fails, the second succeeds (1) Both will fail with StackOverflowError (4) The second fails, the first succeeds (3) Both will succeed 1 2
  • 37.
  • 38.
    TYPE CLASSES POLYMORPHIC FUNCTIONS RETROACTIVE POLYMORPHISM We treattype aliases like abstract virtual functions passing and returning types, for instance: def Prev : Nat def Plus(A: Nat) : Nat VIRTUAL TYPES object Factorial extends App { trait Nat { type Prev <: Nat type Plus[A <: Nat] <: Nat type Times[A <: Nat] <: Nat type Factorial <: Nat } trait _0 extends Nat { type Prev = _0 type Plus[A <: Nat] = A type Times[A <: Nat] = _0 type Factorial = _1 } trait Succ[N <: Nat] extends Nat { type This = Succ[N] type Prev = N type Times[A <: Nat] = A#Plus[N#Times[A]] type Plus[A <: Nat] = N#Plus[Succ[A]] type Factorial = This#Times[Prev#Factorial] } type _1 = Succ[_0] type _2 = Succ[_1] type _3 = Succ[_2] type _4 = Succ[_3] type _5 = Succ[_4] type _6 = Succ[_5] type _7 = Succ[_6] type _8 = Succ[_7] type _9 = Succ[_8] // Calculate 3! = 6 implicitly[_3#Factorial =:= _6] } https://gist.github.com/mkleen/9290750
  • 39.
    TYPE CLASSES POLYMORPHIC FUNCTIONS VIRTUAL TYPES POLYMORPHIC FUNCTIONS https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0 Scala function values are monomorphic due to interface Function1[U,V] { .. }  Shapeless library allows to avoid this limitation  Polymorphic functions allow to process heterogeneous collections (HLists) import poly._ // choose is a function from Sets to Options with no type specific cases object choose extends (Set ~> Option) { def apply[T](s : Set[T]) = s.headOption } scala> choose(Set(1, 2, 3)) res0: Option[Int] = Some(1) scala> choose(Set('a', 'b', 'c')) res1: Option[Char] = Some(a) scala> val sets = Set(1) :: Set("foo") :: HNil scala> val opts = sets map choose // map selects cases of choose for each HList element opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil Define polymorphic function
  • 40.
    TYPE CLASSES POLYMORPHIC FUNCTIONS VIRTUAL TYPES POLYMORPHIC FUNCTIONS https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0 Scala function values are monomorphic due to interface Function1[U,V] { .. }  Shapeless library allows to avoid this limitation  Polymorphic functions allow to process heterogeneous collections (HLists) import poly._ // choose is a function from Sets to Options with no type specific cases object choose extends (Set ~> Option) { def apply[T](s : Set[T]) = s.headOption } scala> choose(Set(1, 2, 3)) res0: Option[Int] = Some(1) scala> choose(Set('a', 'b', 'c')) res1: Option[Char] = Some(a) scala> val sets = Set(1) :: Set("foo") :: HNil scala> val opts = sets map choose // map selects cases of choose for each HList element opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil It behaves like an usual function Define polymorphic function
  • 41.
    TYPE CLASSES POLYMORPHIC FUNCTIONS VIRTUAL TYPES POLYMORPHIC FUNCTIONS https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0 Scala function values are monomorphic due to interface Function1[U,V] { .. }  Shapeless library allows to avoid this limitation  Polymorphic functions allow to process heterogeneous collections (HLists) import poly._ // choose is a function from Sets to Options with no type specific cases object choose extends (Set ~> Option) { def apply[T](s : Set[T]) = s.headOption } scala> choose(Set(1, 2, 3)) res0: Option[Int] = Some(1) scala> choose(Set('a', 'b', 'c')) res1: Option[Char] = Some(a) scala> val sets = Set(1) :: Set("foo") :: HNil scala> val opts = sets map choose // map selects cases of choose for each HList element opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil HList runs polymorphic function It behaves like an usual function Define polymorphic function
  • 42.
    REFERENCES  http://adriaanm.github.io/files/higher.pdf  http://twitter.github.io/scala_school/advanced-types.html http://logji.blogspot.com/2012/11/f-bounded-type-polymorphism-give-up- now.html  http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala- part-12-type-classes.html  https://gist.github.com/mkleen/9290750  http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in- scala/
  • 43.