diff options
Diffstat (limited to 'subprojects/docs/src/learn/language/classes/index.md')
-rw-r--r-- | subprojects/docs/src/learn/language/classes/index.md | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/subprojects/docs/src/learn/language/classes/index.md b/subprojects/docs/src/learn/language/classes/index.md new file mode 100644 index 00000000..73108039 --- /dev/null +++ b/subprojects/docs/src/learn/language/classes/index.md | |||
@@ -0,0 +1,212 @@ | |||
1 | --- | ||
2 | SPDX-FileCopyrightText: 2024 The Refinery Authors | ||
3 | SPDX-License-Identifier: EPL-2.0 | ||
4 | description: Metamodeling in Refinery | ||
5 | sidebar_position: 0 | ||
6 | --- | ||
7 | |||
8 | # Classes and references | ||
9 | |||
10 | Refinery supports _metamodeling_ to describe the desired structure of generated models. | ||
11 | |||
12 | The metamodeling facilities are inspired by object-oriented software and the [Eclipse Modeling Foundation](https://eclipse.dev/modeling/emf/) (EMF) Core, a lightweight framework for data models. | ||
13 | The textual syntax in Refinery for defining metamodels is largely compatible with [Xcore](https://wiki.eclipse.org/Xcore), a textual syntax for EMF metamodels. | ||
14 | |||
15 | ## Classes | ||
16 | |||
17 | Classes are declared with the `class` keyword. | ||
18 | |||
19 | Like in many programming languages, class members are specified between curly braces `{}`. | ||
20 | If a class has no members, the declaration may be terminated with a `.` instead. | ||
21 | |||
22 | ```refinery | ||
23 | % Class with no members. | ||
24 | class Region {} | ||
25 | |||
26 | % Alternative syntax without curly braces. | ||
27 | class State. | ||
28 | ``` | ||
29 | |||
30 | By default, a _new object_ is added to the partial model to represent the instances of a class. | ||
31 | For example, the new objects `Region::new` and `State::new` represent potential instances of the classes `Region` and `State`, respectively: | ||
32 | |||
33 | import NewObjectsSimple from './NewObjectsSimple.svg'; | ||
34 | |||
35 | <NewObjectsSimple /> | ||
36 | |||
37 | As you can see, no new objects represent potential nodes that are instanceof of both `Region` and `State`. | ||
38 | In fact, such instances are not permitted at all. | ||
39 | Each node must the instance of a _single most-specific class:_ | ||
40 | |||
41 | import InvalidInstance from './InvalidInstance.svg'; | ||
42 | |||
43 | <InvalidInstance /> | ||
44 | |||
45 | ### Inheritance | ||
46 | |||
47 | Like in object-oriented programming languages, classes may declare _superclasses_ with the `extends` keyword. | ||
48 | The inheritance hierarchy may not contain any cycles (a class cannot be a superclass of itself), but _multiple inheritance_ is allowed. | ||
49 | |||
50 | Classes that can't be instantiated directly (i.e., a subclass must be instantiated instead) can be marked with the `abstract` keyword. | ||
51 | Such classes do not have a _new object,_ since there are no direct instances to represent. | ||
52 | |||
53 | ```refinery | ||
54 | abstract class CompositeElement. | ||
55 | class Region. | ||
56 | abstract class Vertex. | ||
57 | abstract class RegularState extends Vertex. | ||
58 | class State extends RegularState, CompositeElement. | ||
59 | ``` | ||
60 | |||
61 | Notice that the new object `State::new` is an instance of `CompositeElement`, `Vertex`, `RegularState`, and `State` as well. | ||
62 | |||
63 | import NewObjectsWithInheritance from './NewObjectsWithInheritance.svg'; | ||
64 | |||
65 | <NewObjectsWithInheritance /> | ||
66 | |||
67 | ## References | ||
68 | |||
69 | The graph structure of model generated by Refinery is determined by the _references_ of the metamodel, which will appear as labeled edges between nodes (class instances). | ||
70 | |||
71 | References are declared as class members by providing the _target type,_ and optional _multiplicity,_ and the name of the reference: | ||
72 | |||
73 | ```refinery | ||
74 | class Vertex. | ||
75 | class Transition { | ||
76 | Vertex[1] source | ||
77 | Vertex[1] target | ||
78 | } | ||
79 | ``` | ||
80 | |||
81 | import ReferencesSimple from './ReferencesSimple.svg'; | ||
82 | |||
83 | <ReferencesSimple /> | ||
84 | |||
85 | You may add the `refers` keyword for compatibility with [Xcore](https://wiki.eclipse.org/Xcore). The following specification is equivalent: | ||
86 | |||
87 | ```refinery | ||
88 | class Vertex. | ||
89 | class Transition { | ||
90 | refers Vertex[1] source | ||
91 | refers Vertex[1] target | ||
92 | } | ||
93 | ``` | ||
94 | |||
95 | ### Opposite constraints | ||
96 | |||
97 | The `opposite` keywords specifies that two references are in an _opposite_ relationship, i.e., if one reference is present in a direction, the other must be present between the same nodes in the opposite direction. | ||
98 | |||
99 | ``` | ||
100 | class Vertex { | ||
101 | Transition[] outgoingTransition opposite source | ||
102 | Transition[] incomingTransition opposite target | ||
103 | } | ||
104 | class Transition { | ||
105 | Vertex[1] source opposite outgoingTransition | ||
106 | Vertex[1] target opposite incomingTransition | ||
107 | } | ||
108 | ``` | ||
109 | |||
110 | import ReferencesOppositeInstance from './ReferencesOppositeInstance.svg'; | ||
111 | |||
112 | <ReferencesOppositeInstance /> | ||
113 | |||
114 | Opposites must be declared in pairs: it is a specification error to declare the `opposite` for one direction but not the other. | ||
115 | |||
116 | Unlike in EMF, references that are the `opposite` of themselves are also supported. | ||
117 | These must always be present in both directions between two nodes. | ||
118 | Thus, they correspond to undirected graph edges. | ||
119 | |||
120 | ```refinery | ||
121 | class Person { | ||
122 | Person[] friend opposite friend | ||
123 | } | ||
124 | ``` | ||
125 | |||
126 | import ReferencesOppositeSelf from './ReferencesOppositeSelf.svg'; | ||
127 | |||
128 | <ReferencesOppositeSelf /> | ||
129 | |||
130 | ### Multiplicity | ||
131 | |||
132 | _Multiplicity constrains_ can be provided after the reference type in square braces. | ||
133 | They specify how many _outgoing_ references should exist for any given instance of the class. | ||
134 | |||
135 | :::info | ||
136 | |||
137 | To control the number of _incoming_ references, add an `opposite` reference with multiplicity constraint. | ||
138 | |||
139 | ::: | ||
140 | |||
141 | A multiplicity constraint is of the form `[n..m]`, where the non-negative integer `n` is the _lower_ bound of outgoing references, | ||
142 | and `m` is a positive integer or `*` corresponding to the _upper_ bound of outgoing references. | ||
143 | The value of `*` represent a reference with _unbounded_ upper multiplicity. | ||
144 | |||
145 | If `n` = `m`, the shorter form `[n]` may be used. | ||
146 | The bound `[0..*]` may be abbreviated as `[]`. | ||
147 | If the multiplicity constraint is omitted, the bound `[0..1]` is assumed. | ||
148 | |||
149 | --- | ||
150 | |||
151 | In the following model, the node `v1` satisfies all multiplicity constraints of `outgoingTransition`. | ||
152 | The node `v2` violates the lower bound constraint, while `v3` violates the upper bound constraint. | ||
153 | All `Transition` instances satisfy the multiplicity constrains associated with `source`. | ||
154 | |||
155 | ```refinery | ||
156 | class Vertex { | ||
157 | Transition[2..3] outgoingTransition opposite source | ||
158 | } | ||
159 | class Transition { | ||
160 | Vertex[1] source opposite outgoingTransition | ||
161 | } | ||
162 | ``` | ||
163 | |||
164 | import MultiplicityConstraintsInstance from './MultiplicityConstraintsInstance.svg'; | ||
165 | |||
166 | <MultiplicityConstraintsInstance /> | ||
167 | |||
168 | ### Containment hierarchy | ||
169 | |||
170 | To structure models and ensure their connectedness, Refinery supports _containment_ constraints. | ||
171 | |||
172 | References may be marked as _containment_ references with the `contains` keyword. | ||
173 | |||
174 | Classes that are the _target type_ of at least one _containment_ reference are considered `contained`. | ||
175 | An instance of a `contained` class must have exactly 1 incoming containment reference. | ||
176 | Instances of classes that are not `contained` must _not_ have any incoming containment references. | ||
177 | |||
178 | Containment references have to form a _forest_, i.e., they must not contain any cycles. | ||
179 | The _roots_ of the forest are instances of classes that are not `contained`, while `contained` classes for the internal nodes and leaves of the trees. | ||
180 | |||
181 | Opposites of _containment_ references have to be marked with the `container` keyword. | ||
182 | They must not specify any multiplicity constraint, since the multiplicity is already implied by the containment hierarchy. | ||
183 | |||
184 | --- | ||
185 | |||
186 | In the following model, the instances of `Region` are the roots of the containment hierarchy. | ||
187 | The classes `Vertex` are `Transition` are both considered `contained`. | ||
188 | |||
189 | ```refinery | ||
190 | class Region { | ||
191 | contains Vertex[] vertices opposite region | ||
192 | } | ||
193 | |||
194 | class Vertex { | ||
195 | container Region region opposite vertices | ||
196 | contains Transition[] outgoingTransition opposite source | ||
197 | Transition[] incomingTransition opposite target | ||
198 | } | ||
199 | |||
200 | class Transition { | ||
201 | container Vertex source opposite outgoingTransition | ||
202 | Vertex[1] target opposite incomingTransition | ||
203 | } | ||
204 | ``` | ||
205 | |||
206 | Containment edges are show with **thick** lines: | ||
207 | |||
208 | import ContainmentInstance from './ContainmentInstance.svg'; | ||
209 | |||
210 | <ContainmentInstance /> | ||
211 | |||
212 | Containment edges form trees, while non-containment references, such as `target`, may point across the containment hierarchy. | ||