# Demystifying Jeremy's Interfaces

**URL:** <https://discourse.elm-lang.org/t/demystifying-jeremys-interfaces/8834>\
**Category:** Show and Tell\
**Created:** [December 19, 2022, 8:27am UTC](https://discourse.elm-lang.org/t/demystifying-jeremys-interfaces/8834 "2022-12-19T08:27:01Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![pit](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pit/32/5389_2.png) [@pit](https://discourse.elm-lang.org/u/pit)\
**Post date:** [December 21, 2022, 1:26pm UTC](https://discourse.elm-lang.org/t/demystifying-jeremys-interfaces/8834/4 "2022-12-21T13:26:30Z")

</div>

Thank you, Rupert, for your buffer example. You are a little bit further in your code than I am here, but I’ll catch up in this part.

* * *

## Jeremy’s Original Code

So, after the (maybe not so interesting) introduction, let’s proceed straight to the example from Jeremy’s talk. I recommend reading [his slides](https://docs.google.com/presentation/d/1lTgRyGbswb2ozynYckLUZja_FY5RGlBnfJGduOUsYGc/edit#slide=id.p) first, because I don’t repeat his introduction here.

First, he defines two mutually recursive types:

```elm
type Counter
    = Counter CounterRecord

type alias CounterRecord =
    { up : Int -> Counter
    , down : Int -> Counter
    , value : Int
    }

```

This defines an “interface” named `Counter` together with the functions `up`, `down`, and `value`, all three combined in the `CounterRecord`.

There certainly are similarities between Jeremy’s `Counter` and my introductory `Thing` example:

| | Jeremy | Pit |
| --- | --- | --- |
| Exposed type | `Counter` | `Thing` |
| Exposed functions | `up, down, value` | `thingSize, thingDouble` |
| Underlying types | `Int, List ()` | `String, Int, Char` |

But there are differences. The most important one: in Jeremy’s example, you don’t see the underlying types at all. In fact, I mentioned the underlying types `Int` and `List ()` just because Jeremy used them in his examples, as we’ll see soon, but there could be many more. The definition of the “interface” is totally independent of the actual “implementations”!

* * *

Great, but now the question is: how can I create such a `Counter`?

This is where the magic begins. Here’s Jeremy’s code to create two kinds of `Counter`s:

```elm
intCounter : Int -> Counter
intCounter =
    impl CounterRecord
        |> wrap (\raise rep n -> raise (rep + n))
        |> wrap (\raise rep n -> raise (rep - n))
        |> add identity
        |> map Counter
        |> init (\raise rep -> raise rep)

listCounter : Int -> Counter
listCounter =
    impl CounterRecord
        |> wrap (\raise rep n -> raise (List.repeat n () ++ rep))
        |> wrap (\raise rep n -> raise (List.drop n rep))
        |> add List.length
        |> map Counter
        |> init (\raise n -> raise (List.repeat n ()))

```

Both functions have the same signature: `Int -> Counter`. They return a `Counter` with the given `Int` as the starting value. An `intCounter` allegedly uses the type `Int` internally to represent the counter state, a `listCounter` uses the type `List ()`, with the length of the list representing the counter state. We’ll look at the details of these functions in the next parts…

Here are the helper functions that make it all possible:

```elm
impl : t -> (raise -> rep -> t)
impl constructor =
    \_ _ -> constructor

wrap : (raise -> rep -> t) -> (raise -> rep -> (t -> q)) -> (raise -> rep -> q)
wrap method pipeline raise rep =
    method raise rep |> pipeline raise rep

add : (rep -> t) -> (raise -> rep -> (t -> q)) -> (raise -> rep -> q)
add method pipeline raise rep =
    method rep |> pipeline raise rep

map : (a -> b) -> (raise -> rep -> a) -> (raise -> rep -> b)
map op pipeline raise rep =
    pipeline raise rep |> op

init : ((rep -> sealed) -> flags -> output) -> ((rep -> sealed) -> rep -> sealed) -> flags -> output
init initRep pipeline flags =
    let
        raise : rep -> sealed
        raise rep =
            pipeline raise rep
    in
    initRep raise flags

```

As I’ve already written, at this point in the talk my reaction was simply:

> ⁉

* * *

Before trying to understand **how** this code works, I wanted to check **whether** it works **at all**.

> **Sidemark** : the German translation of “to understand” is “begreifen”. This word contains another German verb: “greifen”, which means “to grab” or “to take hold of”. I like this connection, because in order to understand something it often helps if I can grab it, touch it and play with it.

We have functions to create `Counter`s, but the functions in the `CounterRecord` look a little bit unfamiliar. For example, for a function like `up`, which increases a `Counter`, I’d expect a signature like

```elm
up : Int -> Counter -> Counter

```

but in the `CounterRecord` we have the function

```elm
up : Int -> Counter

```

At this place, it helps to have some OO knowledge. In an object-oriented programming language, for example in Kotlin, we could define a `Counter` interface like this:

```kotlin
interface Counter {
    fun up(n: Int): Counter
    fun down(n: Int): Counter
    val value: Int
}

```

Note that here we have exactly the same function signatures as in Jeremy’s `CounterRecord`!

We continue with the OO example: Whenever I have an object which “implements” the `Counter` interface, then I can call the defined methods **on this object**. For example, in Kotlin, I could write a function to increment a `Counter` like this:

```kotlin
fun increment(counter: Counter): Counter =
    counter.up(1)

```

The function `increment` gets an object named `counter` which implements the `Counter` interface, and returns a new `Counter` object. Internally, it calls the `up` method on the `counter` object using the `counter.up(1)` syntax.

In Elm, the `increment` function could be defined (surprisingly similar) like this:

```elm
increment : Counter -> Counter
increment (Counter counterRecord) =
    counterRecord.up 1

```

> **Takeaway** : Whenever I would call a method on an object implementing an interface in the OO world, in Elm, with Jeremy’s interfaces, I destructure the value to get the record with the functions and then call the appropriate one.

This allows me to implement some more Elm-like `Counter` functions:

```elm
up : Int -> Counter -> Counter
up n (Counter counterRecord) =
    counterRecord.up n

down : Int -> Counter -> Counter
down n (Counter counterRecord) =
    counterRecord.down n

value : Counter -> Int
value (Counter counterRecord) =
    counterRecord.value

```

And now I can start to play with Jeremy’s code.

Let’s create a list of different `Counter` types with different starting values:

```elm
myListOfCounters : List Counter
myListOfCounters =
    [intCounter 1, listCounter 2, intCounter 11, listCounter 12]

```

Now we can check whether they were created with the correct initial values:

```elm
List.map value myListOfCounters
--> [1, 2, 11, 12]

```

Yeah, it seems to work!

Let’s increment them and then get the new values:

```elm
myListOfCounters
    |> List.map (up 3)
    |> List.map value
--> [4, 5, 14, 15]

```

And now decrement:

```elm
myListOfCounters
    |> List.map (down 3)
    |> List.map value
--> [-2, 0, 8, 9]

```

Hmm. At first glance, the second value looks suspicious. “2 - 3” should be “-1” and not “0”. At second glance, the second and fourth `Counter`s have been created with the function `listCounter`, so they internally use a value of type `List ()`, and the length of the list is used to represent the current state of the counter. Since the length of a list can’t be negative, the implementation of `listCounter` isn’t able to represent negative values. The lowest value we can get is “0”.

* * *

Great. The code works as expected!

In case you want to play with the code, too, [Jeremy posted an Ellie](https://ellie-app.com/kj4C4wV74wRa1) with the code from his slides, and [here’s an Ellie](https://ellie-app.com/kvGsqhc8btna1) with my test code so far.

In the next part, we’ll start to get a better understanding of Jeremy’s code as we begin to modify it a little bit.

---

_[View the full topic](https://discourse.elm-lang.org/t/demystifying-jeremys-interfaces/8834)._
