so different polymorphism in scala
Post on 27-Aug-2014
1.375 Views
Preview:
DESCRIPTION
TRANSCRIPT
So different polymorphism
in Scala
Boris Trofimov
@b0ris_1
www.btrofimoff.com
Scala has at least 9 kinds of
polymorphism
Don’t believe?
Let’s dig in
Agenda
Why Scala?
A few words about definition
Classic polymorphism
Parametric polymorphism
Reflection polymorphism
Functional polymorphism
Duck polymorphism
Enhanced Ad-hoc polymorphism
Type class polymorphism
Parametric polymorphism of the 2nd kind
F-bounded polymorphism
Why Scala?
Object-Oriented Meets Functional
Strong Functional
It makes you love your code again
Scalable grammar
Hello Domain Specific Languages (DSL)
Inexhaustible language for every day
Basic Degree
Definition
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
modifications
Classic polymorphism
Ad-hoc
Subtyping
class A{
def method {
...
this.doSomething
...
}
// abstract method
def doSomething
}
class B extends A{
override def doSomething {}
}
class B extends C{
override def doSomething {}
}
class A
class B extends A
class C extends A
class List{
def add(a : A) {
...
}
}
Parametric polymorphism
class MyClass{
def addItem[A](a:A) = {
val list = new ListBuffer[A]
list +=a
list
}
def addItem[B <: ParentClass] (b:B) = {
val list = new ListBuffer[B]
list +=b
list
}
}
Reflection polymorphism (ugly version)
class MyClass{
def doSomething(a: Object){
...
val method = a.getClass().getMethod(“run”, Int);
method.invoke(a, 1);
...
}
}
Functional polymorphism
class A ( sortFunc: List[Int] => List[Int] ){
def doSomething(data : List[Int]) = {
...
sortFunc(data)
...
}
}
object BubbleSort{
def sort(a:List[Int]) : List[Int] = { ... }
}
object QuickSort{
def sort(a:List[Int]) : List[Int] = { ... }
}
object Application{
def main(){
val a = new A(BubbleSort.sort(_))
a.doSomething(List(1,2,3))
}
}
object Sorter{
def sort( list : List[Int],
data : (Int,Int) => Int ) : List[Int] = {
...
}
}
object Application{
def main(){
val list = List(7,8,5,4)
Sorter.sort(list, (a,b) => a-b)
}
}
Hello Scala
or Bachelor degree
Duck 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
Scala structural types
Caution: Reflection!
class MyClass{
def doSomething(a : type { def run(i : Int) } ){
...
a.run(1)
...
}
}
class DuckClass {
def run(i : Int) {
...
}
}
Type constructor polymorphism
trait ParentTrait{
type T
type MapperType =
com.apache.hadoop.Mapper[LongWritable,Text,AvroKey[CharSequence],AvroValue[T]]
type Context = MapperType#Context
...
}
object CustomMapperObject extends ParentTrait{
type T = Pair[String,String]
class CustomMapper extends MapperType {
override def setup(context:Context) = {
...
}
override def map(key:LongWritable, value:Text, context:Context) = {
...
}
}
}
Type variables defined in sibling classes
Building another types dependent on type variables
Enhanced Ad-hoc polymorphism -Intro
Inheritance vs Composition
Mixin pattern – a way to inject
some code into class impl.
Scala supports Mixin (Trait)
Trait – is like interface +
implementation with multiple
trait inheritance and without
head pain
trait Utils{
def printList[A](list: List[A]) =
list.foreach (a => System.Console.println(a))
}
trait LogTrait {
lazy val logger =
LoggerFactory.getLogger(this.getClass.getName)
def setLogLevel(level : Level) =
Logger.getRootLogger.setLevel(level)
}
class MyClass extends LogTrait with Utils{
def do(){
logger.info("hello world!");
printList List(1,2,3,4,5,6)
}
}
Enhanced Ad-hoc polymorphism – Continue
or welcome to 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 {
def main() {
val obj = new OurComponent with ComponentAImpl with ComponentBImpl
println(obj.doSomething())
}
}
Master degree
Type class polymorphism – Intro Way to create generalized methods with partial specialization
Way to have some logic which cannot be added to origin class T (for
instance tricky serialization)
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](x:T, y:T)(implicit engine : NumericLike[T]) = engine.plus(x, y)
}
object Test{
println( Arithmetics.add("Hello", " World") ) // returns HelloWorld
println( Arithmetics.add(2,3) ) // returns 5
// Compile Error, could not find corresponding implicit object
println( Arithmetics.add(123.0, -45.345) )
}
Type class polymorphism – Continue
or inventing DI class ComponentA{
...
}
class ComponentB{
...
}
class ComponentC (implicit componentA: ComponentA, componentB: ComponentB){
...
}
object LiveContext{
implicit val componentA = new ComponentA()
implicit val componentB = new ComponentB()
implicit val componentC = new ComponentC()
}
object TestContext{
implicit val componentA = mock[ComponentA]
implicit val componentB = mock[ComponentB]
implicit val componentC = new ComponentC()
}
Parametric polymorphism of the 2nd kind
Way to build generalized types to take generics as parameters
trait ContainerHandler[M[_]] {
def put[A](x: A): M[A]
def get[A](m: M[A]): A
}
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 }
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)) )
}
}
object Test{
Operations.tupleize(Some(1), Some(2)) // returns Some( (1,2) )
Operations.tupleize(List(1), List (2)) //returns List( (1,2) )
}
trait Ordered[T]{
def compare(that: T): Int
}
class MyContainer extends Ordered[MyContainer] {
def compare(that: MyContainer): Int = { ... }
}
F-bounded polymorphism – Intro
How to define a polymorphic function that, though defined in terms of
a supertype, will when passed a value of some subtype will always
return/take a value of the same subtype as its argument.
Simplest example:
F-bounded polymorphism plus existential types allows building
generalized functions which process collections of different types(!)
F-bounded polymorphism – Continue 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)
}
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 {
def main(argv: Array[String]): Unit = {
Account.debitAll(BigDecimal("10.00"),
List[T forSome { type T <: Account[T] }](
new CheckingAccount(BigDecimal("0"), 10), new SavingAccount(BigDecimal("0"))))
}
}
Referencies
Martin Odersky Programming in Scala
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
Thank you!
Q&A
top related