so different polymorphism in scala

Post on 27-Aug-2014

1.375 Views

Category:

Software

6 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

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