Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

So various polymorphism in Scala

6,744 views

Published on

Scala has at least 11 types of polymorphism. Do not believe? Let's dive in.

Published in: Software, Technology

So various polymorphism in Scala

  1. 1. SO VARIOUS POLYMORPHISM IN SCALA Boris Trofimov @ Sigma Software @b0ris_1
  2. 2. 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
  3. 3. DO YOU ACCEPT SAPIR–WHORF HYPOTHESIS? WHY SCALA CONTEXT MAP POLYMORPHISM DEFINITION BASIC DEGREE BACHELOR DEGREE MAST DEGR WHY SCALA AGENDA
  4. 4. 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
  5. 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. 6. 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
  7. 7. BASIC DEGREE
  8. 8. 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 { … } }
  9. 9. 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
  10. 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. 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. 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. 13. BACHELOR DEGREE
  14. 14. 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!
  15. 15. 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() }
  16. 16. 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" }
  17. 17. 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() ) }
  18. 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. 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. 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. 21. MASTER DEGREE
  22. 22. 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
  23. 23. 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
  24. 24. 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
  25. 25. 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
  26. 26. 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
  27. 27. 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
  28. 28. 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
  29. 29. 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) ) }
  30. 30. 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)) ) } }
  31. 31. 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 }
  32. 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. 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. 34. 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
  35. 35. 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
  36. 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. 37. Ph.D DEGREE
  38. 38. 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
  39. 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. 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. 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. 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. 43. THANK YOU

×