scala #5

11
Scala #5 Cake pattern, path-dependent types, HList

Upload: alexander-podkhalyuzin

Post on 13-Jul-2015

382 views

Category:

Education


3 download

TRANSCRIPT

Page 1: Scala #5

Scala #5Cake pattern, path-dependent types, HList

Page 2: Scala #5

Self type

Можно объявлять зависимости трейта на другие трейты. Это позволяет реализовать DI на уровне языка.trait A

trait B {

this: A =>

}

Page 3: Scala #5

Difference with extends

Почему не подходит extends?В этом случае если в А все методы реализованы, мы можем просто забыть добавить нужный mixin.trait A {

def foo = "It's foo 1"

}

trait B extends A

trait C extends A {

override def foo = "It's foo 2"

}

new B //no compiler error

Page 4: Scala #5

Difference with extends

То есть B не ведёт себя как отдельная компонента, что противоречит идеологии Dependency Injection.

Page 5: Scala #5

Cake patterntrait AComp {

val a: A

class A {

def a() = "It's A"

}

}

trait BComp {

val b: B

class B {

def b() = "It's B"

}

}

trait CComp {

this: AComp with BComp =>

def c() =

"It's C with " + b.b() +

" and " + c.c()

}

new CComp {

val a = new A

val b = new B

}

Page 6: Scala #5

Example

Давайте напишем чайник. У него есть интерфейс с кнопкой. Сервис нагревания. Сервис вычисления количества воды. И сервис проверки, что воды не меньше min и не больше max. А также две реализации чайника с разным min и max. Во втором также есть сервис темературы воды, чайник не включается, если температура выше 98 градусов.

Page 7: Scala #5

Path-dependent types

Напишем математически понятную имплементацию графа:case class Node(id: Int)

case class Edge(left: Node, right: Node)

class Graph(nodes: ArrayBuffer[Node],

edges: ArrayBuffer[Edge]) {

def connect(left: Node, right: Node) {

edges += Edge(left, right)

}

}

Page 8: Scala #5

Path-dependent types

Но лучше было бы запретить на уровне компилятора невозможные действия:class Graph {

case class Node(id: Int)

case class Edge(left: Node, right: Node)

val nodes: ArrayBuffer[Node] = ???

val edges: ArrayBuffer[Edge] = ???

def connect(left: Node, right: Node) {

edges += Edge(left, right)

}

}

Page 9: Scala #5

Другой пример:abstract class Key(id: String) {

type Value

}

class DataStorage {

val data = collection.mutable.Map[Key, Any]

def get(key: Key): Option[key.Value] = ???

def set(key: Key)(value: key.Value) = ???

}

object Keys {

trait StringKey {

this: Key =>

type Value = String

}

val nameKey = new Key("name") with StringKey

}

Abstract types

Page 10: Scala #5

Graph example

Давайте напишем граф, который может быть расширен несколькими вариантами:● Обычный граф● Цветной граф● Ориентированный граф

Page 11: Scala #5

Heterogeneous list

А теперь напишем HList, который состоит из HNil, HCons, а также есть метод concat, который умеет объединять два списка.