ADTs & Typeclasses

in Scala

Jan Schulte

About me

Freelance Scala consultant

Currently Scala lead @ Douglas

Scala UG Düsseldorf (@scaladus)

Idris UG Düsseldorf (@idrisdus)

Algebraic Data Types

In computer programming, more so functional programming and type theory, an algebraic data type is a kind of composite type, i.e., a type formed by combining other types.

Source Wikipedia

Sum Type

Describes + types or logical or types

Thinking in ***is a*** relationships

A TrafficLight is Green or Yellow or Red

A Day is
Monday or Tuesday or Wednesday or
Thursday or Friday or Saturday or

So how do we represent that in Scala?

Sneak peek Scala 3

(aka Dotty)

Product Type

Describes types or logical and types

Thinking in ***has a*** relationships

A Person has a Name and an Age

A Point has an X-coordinate and a Y-coordinate

And now in Scala...

Product type 2.0 aka Records

A Person has a Name and an Age


A result of a computation ***is*** empty ***or*** it ***has*** just a value

A result of a computation ***is*** either a String ***or*** a Double

Recursive types

Source Screenshot (2017-07-05)

A page menu ***is*** either a menu item that ***has*** a title

***or*** a menu category that ***has*** a title and 1..* submenus

Pro tips

#1 - Wrap Sum type in companion object

#2 - Abstract similar Product types

#3 - Parameterize type

#3 - Parameterize type


ADTs: Sum, Product, Recursive...

All nice and shiny...

...but how do we add functionality to our ADTs?

Expression problem


Calculate the area of a shape

Adding subtypes is easy

Adding functions is difficult

GoF Visitor Pattern! Don't you dare!

Typeclasses to the rescue

Concept from FP languages (Haskell)

Separate functionality and data types

Area Typeclass

Typeclasses - Simulacrum

Compiler plugin by Michael Pilquist

Reduce required typeclass boilerplate

import simulacrum._

@typeclass trait JsonSerialisable[A] {
@op("json") def serialise(elem:A): String

implicit val intSerialisable = new JsonSerialisable[Int] {
  override def serialise(elem:Int) = "{\"elem\":"+ elem + "}"

import JsonSerialisable.ops._
1.json // prints {"elem":1}

Show typeclass

Get a textual representation of an object

a.k.a toString

Do you know how toString() is used in your project?

  • Testing
  • Person(Name(Jan),Age(32))
  • Logging
  • Jan[age=32]
  • Json Serialisation

Do you know how toString() is used in your project?

  • Output Css classes (hmmkay)
  • Create Javascript tracking code (seriously?)
  • Create a checksum (dafuq???)

Typelevel Cats library

* A type class to provide textual representation
trait Show[A] {
    def show(f: A): String

Source Cats

Opinionated guideline

#1 - Use typeclasses

...for generic functionality not specific to your data type

@typeclass trait Json[E] {
    @op("json") def toJson(elem: E): String

#2 - Use structural recursion

...for basic data manipulation

trait Shape {
    def map(f: A):Shape = this match {
        case class Rectangle(w,h) => Rectangle(f(w),f(h))
        case class Circle(r) => Circle(f(r))

#3 - Use a helper object

...for one-time functionality specific to your data type

object Calculator {

  def deriveEasterDiscount(price: Price): Discount = ???


Take aways

  • ADTs are simple yet powerful.
  • So go for it! Model your data as ADTs...
  • ...and be dumb! Think in is-a and has-a relationships.
  • ...but keep your ADTs clean...
  • ...and use Typeclasses to add functionality!

Thank you!


Presentation Link: