/ 4 min read
Type Classes, Givens and Extensions in Scala 3
Last Updated:
Recently I have returned to the exploration of Functional Programming in Scala 3. I decided to explore the structure and hierarchy of the Cats library and how the various elements of Category Theory come together.
Directly from the Cats website, ‘Cats is a library which provides abstractions for functional programming in the Scala programming language’.
The fundamental building block of these abstractions is the Type Class.
Type Classes
We use Type Classes to define a ‘kind’ of behaviour. Let’s look at an example:
This type class declares the abstract behavour serialize
. Let’s expand on exactly what that means. It means that if this type class is implemented for some type T
, then type T
would be able to behave in the JSONSerializer
way.
This implies that in order to make use of this class type, we need to implement the class type for some type T
. Let’s do that for Int
.
Now that we have an instance of JSONSerializer[T]
for Int
, we are able to use this instance to call the type class’ methods.
It would be reasonable to define a more general API as follows:
The inconvienience now is that we need to pass the correct JSONSerializer
for the correct type T
of value
. Enter ‘givens’.
Givens
Scala 3 allows us to declare a value as ‘given’, meaning it can be automatically substituted by the compiler into any parameter which is declared as ‘using’ and which has the same type. Let’s look at a simple example:
First we declare the value 5
as a given Int
. This means that for any using
parameter for which this given is in scope and which has a matching type of Int
, the value 5
will be substituted.
When we call our add
function, we do not need to specify the second parameter, since our ‘in scope Int’ of 5
will be substituted.
Using this same technique, we can simplify our previous JSONSerializer
example. We can declare our intJSONSerializer
as a given JSONSerializer[Int]
and then simply let the compiler substitute the function parameter.
This is already better, but since we are operating on a single unary parameter, it would be more convenient if we could call the function as a method on the type T
instead.
Extensions
In order to add methods to existing types, we define an ‘extension’.
Looking at the example below, let’s explain the syntax in English.
Define an extension for any value value
of type T
if a given value (let’s call it serializer
) of type JSONSerializer[T]
exists in scope.
If the above extension clause is true, the compiler will make available the methods defined within the extension body to all instances of type T
.
Complete Example
Let’s now look at the full implementation of our example, with the intermediate explanatory values removed.
Outro
This was an initial look at Type Classes, Givens and Extensions in Scala 3.
In the next chapter I will take a look at the type classes from Category Theory that make up most functional libraries and specifically focus on the Cats library.