# Difference between revisions of "DDC/FieldProjections"

< DDC
Jump to: navigation, search

This is outdated information. The DDC project has moved to http://discus-lang.org

## Data fields

When data types are defined using field names, we can use the projection operator `(.)` to select the fields.

```data Vector
= Vector { x :: Float; y :: Float; }

main ()
= do   vec = Vector 3.0 4.0
out vec.x          -- prints '3.0'
out vec.y          -- prints '4.0'
```

## Custom projections

We can also define our own, custom projections and use `(.)` to select them. A `project` definition is similar to a regular `instance` definition in that it defines a set of functions associated with a particular type (in this case, `Vector`). When we use `(.)`, its first argument is passed as the first argument to our projection function - and so on.

```project Vector where
magnitude :: Vector -> Float
magnitude (Vector x y)
= sqrt (x * x + y * y)

dot :: Vector -> Vector -> Float
dot (Vector x1 y1) (Vector x2 y2)
= x1 * x2 + y1 * y2

main ()
= do   ...
out vec.magnitude               -- prints '5.0'
out vec.dot (Vector 5.0 6.0)    -- prints '39.0'
```

## Projections are type directed

In Disciple we can re-use the same field names in multiple data types, each with different field types. The type system uses the type of the first argument of `(.)` to determine what projection function to use. Alternatively, we can use the `(&)` operator to specify the projection type manually.

```data Location
= Location { x :: String; y :: String; }

main ()
= do   ...
loc = Location "over" "there"
out loc.x                      -- prints 'over'

out \$ magnitude&{Vector} vec   -- prints '5.0'
```

Using `(&)`, we can also use "projection" functions who's first argument is not of the projection type.

```project Vector where
...
new :: Float -> Float -> Vector
new posX posY = Vector posX posY

main ()
= do   ...
vec2  = new&{Vector} 5.0 6.0
```

## Ambiguous projections

As Disciple uses the type of the first argument of `(.)` to decide what projection to use, it needs to be constrained to a data type (not just a type variable). Usually a top level type signature is enough.

Compilation of this function:

```getX thing = thing.x
```

will fail with

```    ./Main.ds: ...
Ambiguous projection: .x
```

as there is no way of knowing what version of `.x` to use, are we talking about the `.x` from `Vector` or `Location`?

Providing a type signature adds the required constraint.

```getx :: Vector -> Float
getX thing = thing.x
```