# Structural links

> The OPM language · https://spoletta.com/docs/structural-links

Structural links join objects to objects. They don't happen, they just hold: what an object is made of, what attributes it exhibits, and what it is a kind of. Together they give an object its shape.

*Diagram: A Car is a Vehicle (hollow triangle), consists of four Wheels and an Engine (filled triangles), and exhibits a Registration (triangle within a triangle).*

## The three structural links

| Link | Symbol | Meaning | In Spoletta |
| --- | --- | --- | --- |
| Exhibition | triangle with a filled triangle inside | The object exhibits an attribute: a ticket's title. | Plain **attributes**, or a part that is *An attribute it exhibits* when the attribute is itself an object (an address with a street and a city). |
| Aggregation | filled triangle | The object consists of parts: a car's wheels, a release's changes. | A part that is *A part it aggregates*. |
| Generalization | hollow triangle | The object is a kind of another and has everything it has: a car is a vehicle. | **Specializes** in the object's settings. |

The triangle always sits under the whole, or the general, with its apex towards it. At a part's end, the board says how many of it make up the whole.

## Unfolding an object

An object's structure is built on a board of its own. Press **Unfold** on the object (or right-click it and choose **Unfold**), and its board shows the object, its parts below it, the object it specializes above it, and objects specializing it beside it. Add a part there, and in the part's settings choose **How it makes up** the whole: **An attribute it exhibits** or **A part it aggregates**.

## What structure means for the JSON

An object with attributes and parts holds a JSON object whose keys are, in order: the fields of the object it specializes, then its own attributes, then its parts. A part that is a list holds an array.

Release, which consists of a list of Change:

```json
{
  "version": "4.12.0",
  "changes": [
    { "title": "Faster search", "link": "https://github.com/acme/shop/pull/812" },
    { "title": "Fix login loop", "link": "https://github.com/acme/shop/pull/815" }
  ]
}
```

> **Watch out:** A part's name can't clash with an attribute of its owner, and parts can't loop. A person never makes up another object.

OPL:

```text
Bug is a Ticket.
Ticket exhibits key and summary.
Release consists of a list of Change.
```

To share one shape between several flows, make it a [struct](https://spoletta.com/docs/structs.md).
