Algebraic Data Types
Model your domain.
Algebraic Data Types is a free Scala for Backend Engineering & Functional Programming lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Scala for Backend Engineering & Functional Programming learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is an ADT?
An algebraic data type (ADT) is a type built by combining other types. In Scala you model ADTs with a sealed trait plus case class and case object variants.
ADTs let you precisely describe the shape of your domain data.
Sum Types
A sum type means a value is one of several alternatives (an OR). A traffic light is Red OR Yellow OR Green.
You express this with a sealed trait and several variants.
sealed trait Light
case object Red extends Light
case object Yellow extends Light
case object Green extends Light
object Main {
def main(args: Array[String]): Unit = {
val l: Light = Yellow
println(l)
}
}Product Types
A product type means a value combines several fields (an AND). A point has an x AND a y.
Case classes are product types.
case class Point(x: Int, y: Int)
object Main {
def main(args: Array[String]): Unit = {
val p = Point(3, 4)
println(s"${p.x} and ${p.y}")
}
}Combining Sum and Product
Real ADTs mix both: a sealed trait (sum) whose variants are case classes (products).
Here a Shape is a Circle (with radius) OR a Rectangle (with width and height).
sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
def main(args: Array[String]): Unit = {
val s: Shape = Rectangle(3, 4)
println(s)
}
}Operating on an ADT
You process an ADT by pattern matching on its variants. Each branch handles one shape.
sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
def area(s: Shape): Double = s match {
case Circle(r) => 3.14159 * r * r
case Rectangle(w, h) => w * h
}
def main(args: Array[String]): Unit = {
println(area(Circle(2)))
println(area(Rectangle(3, 4)))
}
}Modeling a Domain
ADTs make invalid states unrepresentable. Model a payment method as a closed set of valid options.
sealed trait PaymentMethod
case class CreditCard(number: String) extends PaymentMethod
case class BankTransfer(iban: String) extends PaymentMethod
case object Cash extends PaymentMethod
object Main {
def main(args: Array[String]): Unit = {
val m: PaymentMethod = Cash
println(m)
}
}Recursive ADTs
An ADT can refer to itself, which is how you model trees and lists. Here is a simple binary tree.
sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
def main(args: Array[String]): Unit = {
val t: Tree = Node(1, Leaf, Node(2, Leaf, Leaf))
println(t)
}
}Folding Over a Recursive ADT
Recursion plus matching lets you process the whole structure. Here we sum every value in a tree.
sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
def sum(t: Tree): Int = t match {
case Leaf => 0
case Node(v, l, r) => v + sum(l) + sum(r)
}
def main(args: Array[String]): Unit = {
val t = Node(1, Node(2, Leaf, Leaf), Node(3, Leaf, Leaf))
println(sum(t))
}
}Why ADTs?
ADTs are powerful because they:
- Describe data precisely as sums and products
- Make illegal states impossible to construct
- Pair perfectly with exhaustive pattern matching
- Scale to recursive structures like trees and lists
ADTs vs Inheritance
Traditional OOP would scatter behavior across subclasses. ADTs keep data definitions closed and put behavior in functions that pattern match.
This separation of data and behavior is a hallmark of functional design.
Putting It Together
A complete small ADT with a function that handles every variant.
sealed trait Json
case class JNum(n: Double) extends Json
case class JStr(s: String) extends Json
case object JNull extends Json
object Main {
def render(j: Json): String = j match {
case JNum(n) => n.toString
case JStr(s) => "\"" + s + "\""
case JNull => "null"
}
def main(args: Array[String]): Unit = {
List(JNum(3.0), JStr("hi"), JNull).foreach(j => println(render(j)))
}
}Quick Check
Test your understanding of ADTs.
Recap
You learned to build algebraic data types:
- Sum types: sealed trait with multiple variants (OR)
- Product types: case classes with fields (AND)
- Combine them to model domains precisely
- ADTs can be recursive (trees, lists)
- Process them with pattern matching
Frequently asked questions
Is the “Algebraic Data Types” lesson free?
Yes — the full text of “Algebraic Data Types” is free to read here on the web, and the Scala for Backend Engineering & Functional Programming course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Scala for Backend Engineering & Functional Programming course, upgrade to CoddyKit PRO.
What will I learn in “Algebraic Data Types”?
Model your domain. You practise Scala for Backend Engineering & Functional Programming with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Scala for Backend Engineering & Functional Programming?
No prior experience is required. Scala for Backend Engineering & Functional Programming on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Algebraic Data Types” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Scala for Backend Engineering & Functional Programming lesson?
Yes. Every Scala for Backend Engineering & Functional Programming lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Case Classes
- Sealed Traits
- Algebraic Data Types
- Exhaustive Matching