# Abstract data types

Sometimes we wish to define a data type that does not expose its
representation. Such data types are called *abstract* or *opaque*.
Suppose we wish to define operations on normalised vectors in 2D
space. If we
directly exposed the representation, then it would be easy to
accidentally break normalisation. To avoid mistakes, we need all
operations to go through functions that are careful to re-normalise
when needed.

In Futhark, this kind of information hiding is done via the module
system. First we define a *module type* that describes an
interface consisting of abstract types and operations on those
types:

```
module type normvec = {
type vec
val mk : {x: f64, y: f64} -> vec
val unmk : vec -> {x: f64, y: f64}
val add : vec -> vec -> vec
}
```

The module type states that there is some abstract type `vec`

, a
function `mk`

that can turn records into
`vec`

s, and a function `unmk`

that can turn `vec`

s into records.
The idea is that the `mk`

function will perform normalisation. The
module type also specifies a function `add`

for adding normalised
vectors. This is of course a much smaller set of operations than
you’d need for real programming, but it’s enough to show the idea.

We can define a module that *implements* the `normvec`

module type
like this:

`module normvec : normvec = {`

Note that module names and module type names live in different namespaces, and there is no requirement that the name of a module must match the module type it is implementing.

We first define the `vec`

type, as a record.

`type vec = {x: f64, y: f64} `

The definition of `vec`

is visible inside the module itself, but
outside users are only able to use it through the operations
specified by the `normvec`

module type.

The `mk`

function normalises the given coordinates.

```
def mk {x, y} : vec =
let norm = f64.sqrt (x**2+y**2)
in {x = x / norm, y = y / norm}
```

The `unmk`

function just returns the coordinates.

`def unmk {x, y} = {x, y} `

Finally, the `add`

function adds the components, then re-normalises
the vector.

```
def add (a: vec) (b: vec) : vec =
2, y = (a.y+b.y)/2}
{x = (a.x+b.x)/
}
```

Now we can use the module as e.g:

```
> let a = normvec.mk {x=2,y=1}
> let b = normvec.mk {x=2,y=10}
> let c = normvec.add a b
> normvec.unmk c
{x = 0.54527166306905f64, y = 0.7138971355954391f64}
```

If we directly tried to access `a.x`

, we would get a type error.

Note that if you actually load this into `futhark repl`

to play
around with it, you’ll be able to directly observe the contents of
`normvec.vec`

values. To ease debugging, the interpreter does not
respect abstraction boundaries when prettyprinting.

# See also

Complex numbers, Triangular arrays, Nominal types, AD with dual numbers, Three-dimensional vectors.

Reference manual: Module System.