##
Thought Experiment: Interfaces in APIs

We’re still in story-telling mode…

Rupert is thinking about new use cases for the interface technology. The technology itself can be used to hide an internal type behind an interface. But we can make the interface type itself opaque and hide the usage of the whole interface technology behind a module API.

Rupert wants to try this with a real example, and it doesn’t take him long to implement something. He shows the new module to his colleague Pit.

*Rupert*

Hey Pit, let me show you my new “BitShifter” service! Here’s the module definition:

```
module BitShifter exposing
( BitShiftable, Operations
, shiftLeftBy, shiftRightBy, toBitShiftable
)
```

It lets you turn any type you like into a `BitShiftable`

, a value that you can then shift left and shift right, just like the bit shift methods in the `Bitwise`

core module.

The type `BitShiftable`

is opaque. You don’t need to know the exact implementation in order to use it. Such a value can be shifted bitwise with the functions

```
shiftLeftBy : Int -> BitShiftable -> BitShiftable
shiftRightBy : Int -> BitShiftable -> BitShiftable
```

Isn’t this great?

You just have to tell the service a little bit about your type. The `Operations`

record specifies what the service wants to know about your type in order to be able to to turn it into a `BitShiftable`

:

```
type alias Operations a =
{ up : Int -> a
, down : Int -> a
, value : Int
}
toBitShiftable : (a -> Operations a) -> a -> BitShiftable
```

So if you tell me how to create the `up`

, `down`

, and `value`

fields for any value of your type `a`

, plus a concrete `a`

value, I can turn the latter into a `BitShiftable`

!

*Pit*

Hey, this is nice, Rupert! But you can’t trick me The `Operations`

record told me your secret: you are using an interface behind the scenes, aren’t you?

*Rupert*

Hmm…

*Pit*

No problem. Let’s pretend I don’t know. I’ll test your service right away with my favorite type: a list of units…

Let me see… I’ll give you the operations and you turn my `List ()`

into a `BitShiftable`

…

He writes:

```
myBitShiftable : BitShifter.BitShiftable
myBitShiftable =
BitShifter.toBitShiftable
(\list ->
{ up = \n -> List.repeat n () ++ list
, down = \n -> List.drop n list
, value = List.length list
}
)
[ (), (), () ]
```

*Pit*

And now I can shift it left and right, right?

```
shifted : BitShifter.BitShiftable
shifted =
myBitShiftable
|> BitShifter.shiftLeftBy 2
|> BitShifter.shiftRightBy 1
```

Nice! But what can I do with the shifted result? Can I get it back as a `List ()`

to be able to look at it? What about a function like

```
fromBitShiftable : BitShiftable -> a
```

Rupert, who is a little disappointed about the course of the experiment, doesn’t want to give up yet, so he just says:

A function with this signature wouldn’t be possible, but let me think about it…

Of course he has been using the interface technology behind the scenes. Here’s his code:

```
type BitShiftable
= BitShiftable (Operations BitShiftable)
type alias Operations a =
{ up : Int -> a
, down : Int -> a
, value : Int
}
bitShiftableOps : (rep -> typ) -> Operations rep -> Operations typ
bitShiftableOps raise ops =
{ up = ops.up >> raise
, down = ops.down >> raise
, value = ops.value
}
toBitShiftable : (a -> Operations a) -> a -> BitShiftable
toBitShiftable impl =
IF.create BitShiftable bitShiftableOps impl
shiftLeftBy : Int -> BitShiftable -> BitShiftable
shiftLeftBy n (BitShiftable ops) =
ops.up (ops.value * (2 ^ max n 0) - ops.value)
shiftRightBy : Int -> BitShiftable -> BitShiftable
shiftRightBy n (BitShiftable ops) =
ops.down (ops.value - (ops.value // (2 ^ max n 0)))
```

Nothing special so far. He even used the same operations as in the `Counter`

interface to implement the bit shift operations. It’s no surprise that even Pit was able to see through the secret.

When he said that the `fromBitShiftable`

function from above wouldn’t be possible, he was right. What type should the function result be? It can’t simply be an `a`

like Pit suggested, because the `a`

could be anything.

But Rupert has an idea: what if the `BitShiftable`

type had a type parameter? A function like this would be possible to implement in Elm:

```
fromBitShiftable : BitShiftable a -> a
```

On the other hand, this would mean that the underlying type wouldn’t be hidden anymore, so it wouldn’t be possible to create a list of different `BitShiftable`

s anymore. For Rupert’s `BitShifter`

service, this wouldn’t be a problem. The goal of the service is to enable bit-shifting-like operations for a user-supplied type, not to make multiple different `BitShiftable`

values combinable.

Great. Rupert has a plan how to proceed.

So how could he implement the `fromBitShiftable`

function? He starts with a version that looks like the `value`

function from the `Counter`

interface:

```
fromBitShiftable : BitShiftable a -> a
fromBitShiftable (BitShiftable ops) =
ops.internal
```

OK. So he needs an `Operations`

record with an additional `internal`

field:

```
type alias Operations a =
{ up : Int -> a
, down : Int -> a
, value : Int
, internal : a
}
```

The new field has to be dealt with in the `map`

-like `bitShiftableOps`

function:

```
bitShiftableOps : (rep -> typ) -> Operations rep -> Operations typ
bitShiftableOps raise ops =
{ up = ops.up >> raise
, down = ops.down >> raise
, value = ops.value
, internal = ops.internal
}
```

Hmm. This doesn’t compile. To make the compiler happy, Rupert would have to `raise`

the internal value, too. But he doesn’t want to change the type of the `internal`

value.

Rupert knows how to deal with this problem: he has to introduce an additional type parameter to the `Operations`

record type, too:

```
type alias Operations i a =
{ up : Int -> a
, down : Int -> a
, value : Int
, internal : i
}
```

Now he can leave the `internal`

value as it is without having to apply the `raise`

function:

```
bitShiftableOps : (rep -> typ) -> Operations rep rep -> Operations rep typ
bitShiftableOps raise ops =
{ up = ops.up >> raise
, down = ops.down >> raise
, value = ops.value
, internal = ops.internal
}
```

This compiles! The `BitShiftable`

type now looks like this:

```
type BitShiftable a
= BitShiftable (Operations a (BitShiftable a))
```

Great! Now the `toBitShiftable`

function:

```
toBitShiftable : (a -> Operations a a) -> a -> BitShiftable a
toBitShiftable impl =
IF.create BitShiftable bitShiftableOps impl
```

Only the function signature had to be changed. Nice.

But Rupert knows: if I show Pit this new version, he’ll still be able to figure out what I’ve done just by looking at the types of the `toBitShiftable`

function.

Wouldn’t it be nice if Rupert could use the same `Operations`

record as before in his `BitShifter`

API?

Here’s how the user-supplied `impl`

parameter looked like in the old and in the new version:

```
old:
a ->
{ up : Int -> a
, down : Int -> a
, value : Int
}
new:
a ->
{ up : Int -> a
, down : Int -> a
, value : Int
, internal : a
}
```

Wait… Rupert is sure that he can turn the former into the latter!

He defines two different operations record types: one which is externally visible and an internal one:

```
type alias Operations a =
{ up : Int -> a
, down : Int -> a
, value : Int
}
type alias InternalOperations i a =
{ up : Int -> a
, down : Int -> a
, value : Int
, internal : i
}
```

Now he can convert the original `impl`

parameter with the `Operations`

record into a version using the new `InternalOperations`

record:

```
internalImpl : (a -> Operations a) -> a -> InternalOperations a a
internalImpl impl a =
{ up = (impl a).up
, down = (impl a).down
, value = (impl a).value
, internal = a
}
```

Using this helper function, we get almost the original version of the `toBitShiftable`

function:

```
toBitShiftable : (a -> Operations a) -> a -> BitShiftable a
toBitShiftable impl =
IF.create BitShiftable bitShiftableOps (internalImpl impl)
```

After all, this was easy!

Rupert shows Pit the new version of the `BitShifter`

module.

*Rupert*

Hi Pit. Do you remember the `fromBitShiftable`

function you wanted to have to be able to get back at the shifted value?

I told you that it wouldn’t be possible to implement it in the way you suggested. But if we add a type variable to the `BitShiftable`

type, then I can give you a function

```
fromBitShiftable : BitShiftable a -> a
```

*Pit*

Hmm, OK, so what would I have to change in my code?

*Rupert*

As I said: you have to add a type parameter.

*Pit*

Wait. That’s all I need to do? Everything else stays the same? If this is true, then you’re slowly but surely turning into a type system wizard like Jeremy!

Let me try it…

He adds the type parameter to his code:

```
myBitShiftable : BitShifter.BitShiftable (List ())
myBitShiftable =
BitShifter.toBitShiftable
(\list ->
{ up = \n -> List.repeat n () ++ list
, down = \n -> List.drop n list
, value = List.length list
}
)
[ (), (), () ]
shifted : BitShifter.BitShiftable (List ())
shifted =
myBitShiftable
|> BitShifter.shiftLeftBy 2
|> BitShifter.shiftRightBy 1
```

*Pit*

And now I can get back the original and the bit-shifted value?

He types:

```
myBitShiftable
|> BitShifter.fromBitShiftable
--> [(), (), ()]
shifted
|> BitShifter.fromBitShiftable
--> [(), (), (), (), (), ()]
```

*Pit*

Jeremy, um, I mean, Rupert, you are a genius!

I can’t wait until you explain your wizardry to me!

Rupert smiles. Mission completed.

-- ::: --

Ok, this was the last aspect of the interface technology I wanted to look at. I found it interesting that you can hide a set of user-supplied functions behind an easy-to-use interface type, and that you can hide them from both the users of a module as well as from the module code itself.

In the `BitShifter`

example, both the module user as well as other module functions can use this simple interface:

```
type BitShiftable a
shiftLeftBy : Int -> BitShiftable a -> BitShiftable a
shiftRightBy : Int -> BitShiftable a -> BitShiftable a
```

In the next days, I’ll add a short recap with the three versions of Jeremy’s magic interface functions we’ve seen before, … and then one last thing.