A type class is an abstract, parameterized type that lets you add new behavior to any closed data type without using sub-typing.
If you are coming from Java, you can think of type classes as something like java.util.Comparator[T]
.
The paper “Type Classes as Objects and Implicits” (2010) by Oliveira et al. discusses the basic ideas behind type classes in Scala. Even though the paper uses an older version of Scala, the ideas still hold to the current day.
This style of programming is useful in multiple use-cases, for example:
- Expressing how a type you don’t own—such as from the standard library or a third-party library—conforms to such behavior
- Adding behavior to multiple types without introducing sub-typing relationships between those types (i.e., one
extends
another)
In Scala 3, type classes are just traits with one or more type parameters, like the following:
trait Show[A]:
def show(a: A): String
Instances of Show
for a particular type A
witness that we can show (i.e., produce a text representation of) an instance of type A
.
For example, let’s look at the following Show
instance for Int
values:
class ShowInt extends Show[Int]:
def show(a: Int) = s"The number is ${a}!"
We can write methods that work on arbitrary types A
constrained by Show
as follows:
def toHtml[A](a: A)(showA: Show[A]): String =
"<p>" + showA.show(a) + "</p>"
That is, toHtml
can be called with arbitrary A
as long as you can also provide an instance of Show[A]
.
For example, we can call it like:
toHtml(42)(ShowInt())
// results in "<p>The number is 42!</p>"
Automatically passing type class instances
Since type classes are a very important way to structure software, Scala 3 offers additional features that make working with them very convenient. We discuss these additional features (which fall into the category of Contextual Abstractions) in a later chapter of this book.
Contributors to this page:
Contents
- Introduction
- Scala Features
- Why Scala 3?
- A Taste of Scala
- Hello, World!
- The REPL
- Variables and Data Types
- Control Structures
- Domain Modeling
- Methods
- First-Class Functions
- Singleton Objects
- Collections
- Contextual Abstractions
- Toplevel Definitions
- Summary
- A First Look at Types
- Control Structures
- Domain Modeling
- Tools
- OOP Modeling
- FP Modeling
- Methods
- Method Features
- Main Methods in Scala 3
- Summary
- Functions
- Anonymous Functions
- Function Variables
- Eta Expansion
- Higher-Order Functions
- Write Your Own map Method
- Creating a Method That Returns a Function
- Summary
- Packaging and Imports
- Scala Collections
- Collections Types
- Collections Methods
- Summary
- Functional Programming
- What is Functional Programming?
- Immutable Values
- Pure Functions
- Functions Are Values
- Functional Error Handling
- Summary
- Types and the Type System
- Inferred Types
- Generics
- Intersection Types
- Union Types
- Algebraic Data Types
- Variance
- Opaque Types
- Structural Types
- Dependent Function Types
- Other Types
- Contextual Abstractions
- Given Instances and Using Clauses
- Type Classes
- Context Bounds
- Given Imports
- Extension Methods
- Implementing Type Classes
- Multiversal Equality
- Implicit Conversions
- Summary
- Concurrency
- Scala Tools
- Building and Testing Scala Projects with sbt
- Worksheets
- Interacting with Java
- Scala for Java Developers
- Scala for JavaScript Developers
- Scala for Python Developers
- Where To Go Next