introduction to type classes in scala

18
type classes in Scala And how Json Reads/Writes/Formats work in play framework? Yann Simon - @simon_yann

Upload: yanns

Post on 29-Jan-2018

930 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Introduction to type classes in Scala

type classes in ScalaAnd how Json Reads/Writes/Formats

work in play framework?

Yann Simon - @simon_yann

Page 2: Introduction to type classes in Scala

toString, hashCode on modelcase class Person(name: String, age: Int) val persons = List( Person("bob", 34), Person("alice", 34))

persons.toString()res0: String = List(Person(bob,34), Person(alice,34))

persons.hashCode() res1: Int = -408691241

Page 3: Introduction to type classes in Scala

persons.toStringtoString()List

Person

String Int

toString()

toString() toString()

Page 4: Introduction to type classes in Scala

persons.hashCodehashCodeList

Person

String Int

hashCode

hashCode hashCode

Page 5: Introduction to type classes in Scala

What about persons.toJson? persons.toXML? .toCSV? persons.otherHashCode? persons.otherToString?

Page 6: Introduction to type classes in Scala

Why persons.toString? persons.hashCode?

• part of the standard JVM library package java.lang; public class Object {

public native int hashCode();

public boolean equals(Object obj) { … }

public String toString() { … }

public final native void notify(); public final native void notifyAll();

public final native void wait(long timeout) throws InterruptedException; public final void wait(long timeout, int nanos) throws InterruptedException { … } public final void wait() throws InterruptedException { … } }

Page 7: Introduction to type classes in Scala

Why persons.toString? persons.hashCode?

• needed by Map, Set, serialization…

• mix technical concerns with domain model

• no liberty for further improvement

• ex: #2011-003 multiple implementations denial-of-service via hash algorithm collisionA variety of programming languages suffer from a denial-of-service (DoS) condition against storage functions of key/value pairs in hash data structures, the condition can be leveraged by exploiting predictable collisions in the underlying hashing algorithms.

Page 8: Introduction to type classes in Scala

a good toJson?

• Separated from domain model

• Flexible

• User can override library choices

Page 9: Introduction to type classes in Scala

persons to json

List

Person

String Int

listToJson

personToJson

stringToJson intToJson

trait toJson[A]

Page 10: Introduction to type classes in Scala

ToJson[A] strategy is a parameter of toJson[A]

def toJson[A](a: A)(serializer: ToJson[A]): String = serializer.serialize(a)

toJson("hello")(stringToJson)toJson(3)(intToJson)toJson(Person("bob", 34))(personToJson)toJson(persons)(listToJson(personToJson))

Page 11: Introduction to type classes in Scala

find the right ToJson[A] based on type

def toJson[A](a: A)(implicit serializer: ToJson[A]): String = serializer.serialize(a)

toJson("hello") toJson(3) toJson(Person("bob", 34)) toJson(persons)

Page 12: Introduction to type classes in Scala

find the right ToJson[A] based on type

toJson("hello") // is different from toJson(3)

$ scalac -Xprint:4 Test.scala […] Test.this.toJson[String]("hello")(Test.this.stringToJson); Test.this.toJson[Int](3)(Test.this.intToJson);

Page 13: Introduction to type classes in Scala

Type classes• Define a contract (ex in ToJson[A]: (a: A) -> String)

• Define strategy for a tree of classes (like the domain model)

• Use type for find the suitable implementation

• Each implicit can be overridden / set explicitly => the user has the power to override defaults

• Type classes resolved at compilation time

• Be sure that the strategy is defined for each class

• No runtime introspection necessary

Page 14: Introduction to type classes in Scala

In Play! frameworkpackage play.api.libs.json

object Json {

def toJson[T](o: T)(implicit tjs: Writes[T]): JsValue = tjs.writes(o) def fromJson[T](json: JsValue)(implicit fjs: Reads[T]): JsResult[T] = fjs.reads(json) }

/** * Default Serializers. */trait DefaultWrites { implicit object IntWrites extends Writes[Int] { def writes(o: Int) = JsNumber(o) }

implicit object StringWrites extends Writes[String] { def writes(o: String) = JsString(o) }

implicit def traversableWrites[A: Writes] = new Writes[Traversable[A]] { def writes(as: Traversable[A]) = JsArray(as.map(toJson(_)).toSeq) }}

Page 15: Introduction to type classes in Scala

In Play! frameworkpackage play.api.libs.json

trait Format[A] extends Writes[A] with Reads[A]

/** * Default Json formatters. */trait DefaultFormat { implicit def GenericFormat[T](implicit fjs: Reads[T], tjs: Writes[T]): Format[T] = { new Format[T] { def reads(json: JsValue) = fjs.reads(json) def writes(o: T) = tjs.writes(o) } }}

Page 16: Introduction to type classes in Scala

implicitly syntaxdef toJson[A](a: A)(implicit toJson: ToJson[A]): String = toJson.serialize(a)

// can be written as:def toJson[A : ToJson](a: A): String = implicitly[ToJson[A]].serialize(a)

toJson("hello") toJson(3) toJson(Person("bob", 34)) toJson(persons)

Page 17: Introduction to type classes in Scala

persons.toJsonimplicit class JsonOps[A](a: A)(implicit ser: ToJson[A]) { def toJson: String = ser.serialize(a)} "hello".toJson3.toJsonPerson("bob", 34).toJsonpersons.toJson

Page 18: Introduction to type classes in Scala

Questions?

• code on https://github.com/yanns/scala-type-classes-demo

• more info:

• https://non.github.io/cats/typeclasses.html

• http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html