---
title: Types without values
teaser: A look at value-less types such as Elm's `Never`.
tags: web,elm
author: Joël Quenneville
published_on: 2019-10-30
---

One helpful way to think about types is to consider its [cardinality] — that is,
how many possible distinct values does it have?

For example in Elm, this custom `Direction` type has exactly 4 distinct values
that can be constructed (you could say it has a cardinality of 4).

```elm
type Direction
  = North
  | South
  | East
  | West
```

![Weathervane](https://images.thoughtbot.com/jq-never-types/ulRdGEjDQtOxz36oYaRp_weathervane.jpg)
_Photo by [Jordan Ladikos] on Unsplash_

Similarly, we can say the `Bool` type has two distinct values (`True` and
`False`). The empty tuple `()` type has single possible value - an empty
tuple.

We've seen it's possible to create types with cardinalities of 4, 2, and 1. You
may wonder, is it possible to create a type that has _zero_ possible values?

[cardinality]: https://guide.elm-lang.org/appendix/types_as_sets.html
[Jordan Ladikos]: https://unsplash.com/@jordanladikos

## Never

Elm has a type [`Never`] that does just that. The type name `Never` can still be
used in function signatures but it's impossible to actually create a value of
type `Never`.

This is done with a clever trick. The definition looks like this:

```elm
type Never = JustOneMore Never
```

This type is defined [recursively]. Because there is no base case, constructing
a value of type `Never` is an infinite job.

```elm
aNeverValue : Never
aNeverValue =
  JustOneMore (JustOneMore (JustOneMore ...) )
```

[`Never`]: https://package.elm-lang.org/packages/elm/core/latest/Basics#Never
[recursively]: https://gist.github.com/JoelQ/6b303d9ad450537163b6f8f6cf8a4ed8#recursive-type

## Uses

So it's possible to create a type with zero values. Is this more than just a
curiosity? Is it actually useful? Yes.

The `Never` type is really valuable when trying to _constrain_ the signatures of
other types. For example [`Task.perform`] from [`elm/core`]:

```elm
perform : (a -> msg) -> Task Never a -> Cmd msg
```

This signature says that `perform` can only be called on tasks that _cannot_
fail. All other tasks have to use the `attempt` function that will force you to
do some error handling. That's a really useful distinction to be able to make!

[`Task.perform`]: https://package.elm-lang.org/packages/elm/core/latest/Task#perform
[`elm/core`]: https://package.elm-lang.org/packages/elm/core/latest

## Use with phantom types

[Phantom types] are types that declare a [type parameter] but never use it. For
example:

```elm
-- The `a` is never used anywhere

type Currency a
  = Currency Int
```

We would like to be able to create types like `Currency Dollar` or `Currency
Euro`.  We could create our own `Dollar` or `Euro` types. Since we only care
about the type in the signature and not in the body, we can do some fanciness to
create types that can _never be instantiated_.

To accomplish this we can define these types as infinitely recursive, similar
to Elm's `Never` type. Just like `Never`, `Dollar` and `Euro` can never be
instantiated.

```elm
-- These two types are infinitely recursive.
-- Similar to `Never`, they can never be instantiated.

type Dollar
  = OneMoreDollar Dollar

type Euro
  = OneMoreEuro Euro
```

[Phantom types]: https://thoughtbot.com/blog/modeling-currency-in-elm-using-phantom-types
[type parameter]: https://guide.elm-lang.org/types/reading_types.html#type-variables
