# A Guide to Scala 3

#### Muhammad Tabaza

CTO of PragmaScala 3 comes with many amazing new features. This article attempts to explain the most notable ones, so it is by no means comprehensive. It is, however, a very good introduction to these concepts for beginner to intermediate-level Scala programmers.

At the time of this writing, Scala 3 isnâ€™t actually officially released. However, all the features that would be in Scala 3 are available in Dotty, so weâ€™ll be using it instead.

The examples in this article are on GitHub, and in order to run them, you can clone the repository and run `sbt console`

:

##### note

If you use Visual Studio Code, and you have it on the PATH (i.e. the code command is available globally,) you can run sbt launchIDE to get a better editing experience.

## Intersection Types

Consider the following definitions:

If we think of types in terms of sets, a type would be a collection of elements that satisfy certain properties. For an element to be a member of type `A`

, it has to have the property `a`

of type `String`

. The same goes for elements of type `B`

.

Since types are just sets, what would the *intersection* of `A`

and `B`

be? Well, itâ€™s the set of elements that satisfy the properties of both `A`

and `B`

. We can denote such a type as `A & B`

(the intersection type of `A`

and `B`

,) and we can use it to specify data types such as the type of the argument c in:

We can create an instance of `A & B`

by creating a subtype of both `A`

and `B`

:

Which can be passed to `f`

:

Intersection types are actually the equivalent of compound types, so both `A & B`

and `A with B`

are the same type. However, the `with`

syntax will be deprecated in future versions of Scala.

## Union Types

In Scala, we can express that a value can be either of type `A`

or of type `B`

as `Either[A, B]`

. Consider this example:

The `Either`

type has two variants: `Left`

, and `Right`

. In the case of `E`

, `Left`

represents the variant that carries a value of type `A`

, while `Right`

carries a value of type `B`

(notice the order of the type arguments passed to `Either`

.)

Letâ€™s say that we want to define a function `g`

of `E`

. In order to deal safely with values of `E`

, we would need to do some pattern matching:

This is great! We can safely express values that belong to one of two types. But there are a few problems with `Either`

:

- Itâ€™s not commutative (
`Either[A, B]`

is not`Either[B, A]`

) - It sucks for working with values that can be of three or more types (I mean,
`Either[A, Either[B, Either[Float, Boolean]]]`

? This is a nightmare!)

While still thinking of types as sets, letâ€™s think of `Either[A, B]`

as the *union* of the sets `A`

and `B`

(the set containing all elements of both `A`

and `B`

.) This union can be expressed as `A | B`

:

Union types solve the two problems listed above, and theyâ€™re actually more pleasant to look at and deal with. Consider the definition of `h`

:

Which can be applied with simple arguments (no need to wrap in `Left`

or `Right`

.) For example:

## Enums

Enums are definitions of typesâ€™ values by name. Theyâ€™re useful when a value of a particular type can be one of a well-defined finite set of elements. For example, the definition of WeekDay:

Enum values can be parameterized in order to implement *algebraic data types* (*products*, to be specific.) In Scala 2.x, we encode ADTs as case classes (or tuples,) and sealed traits. Letâ€™s consider a definition of logical expressions:

Now we can evaluate the expression:

Which is just `true âˆ§ Â¬false âˆ¨ true`

. Notice how weâ€™ve had to define a `case class`

for each variant of `VerboseLogicalExpression`

, and made it extend the `trait`

. We also did the same with `Factor`

just to get the behavior of `ConstFactor | NotFactor`

.

Using enums, we can define logical expressions as:

Much cleaner! Note that using the `apply`

method of an `enum`

â€™s variant would return a value of the enum type, not the specific case type. We can use `new`

to use the constructor of the specific type. So we would define a value of type `LogicalExpression.Expr`

as:

## Givens

Givens are definitions that can be used implicitly. In many ways, they are a more refined version of Scala 2.xâ€™s implicits. Consider this example:

Here, we define a *given instance* of an `Add[C]`

. This is a more straightforward way of implementing *type classes*.

##### note

Givens do not need to have names, since their type is all that matters in most cases.

We can define functions that have given parameters to summon any defined given instance:

Similarly, we can define given value aliases:

Implicit conversions are replaced with the definition of a given instance of `Conversion[T, U]`

. For example, we can define an implicit conversion from `String`

to `A`

as:

Using wildcard syntax in imports will not import any given definitions. Instead, you must use `.given`

syntax, or import the given definitions by name. See here for more information about imports.

## Extension Methods

Scala 3 offers a really simple way to add new methods to existing types. Consider the following example:

This definition (when in scope,) adds the `+`

method to any type `T`

for which a given instance of `Add[T]`

is defined, such as the type `C`

.

In 2.x, you would have to define an implicit class with the extension method defined on it to achieve this. This is a much simpler approach.

## Conclusion

There still are many features not covered here: typeclass derivation, match types, and an entirely new macro system, just to name a few. This article would need to be much longer than this in order to cover all of them. Luckily, the documentation offers a great introduction to these concepts, even though it might be lacking in some regards, but thatâ€™ll surely get better with the official release of Scala 3.