Skip to content

Commit e0765f4

Browse files
committed
Suggested editorial changes for Component_Access_To_Rec_Objs chapter
I found the use of "Enclosing" as a type name confusing, and so suggested replaceing "Enclosing" with "Device" and then using "Encloser" rather than "Instance" as the discriminant name. I also think the discussion of immutably limited, aliasedness, etc., is probably more than necessary, and was a bit imprecise in various ways. I have made some fixes, but I think you could probably simplify the whole discussion without losing much.
1 parent ede12ce commit e0765f4

File tree

1 file changed

+49
-44
lines changed

1 file changed

+49
-44
lines changed

content/courses/ada-idioms/chapters/component_access_to_rec_objs.rst

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ We would want a task type or protected type record component when:
2323
object. The record object and contained task/PO object pair is a
2424
functional unit, independent of all other such units.
2525

26-
This idiom applies to both enclosed task types and protected types, but for the
27-
sake of concision let's assume the record component will be of a protected
26+
This idiom applies to both enclosed task types and protected types, but for simplicity let's assume the record component will be of a protected
2827
type.
2928

3029
As part of a functional unit, the PO component will almost certainly be
@@ -99,65 +98,65 @@ two parts:
9998
.. code-block:: ada
10099
101100
package P is
102-
type Enclosing is tagged limited private;
101+
type Device is tagged limited private;
103102
private
104103
105-
protected type Controller (Instance : not null access Enclosing) is
104+
protected type Controller (Encloser : not null access Device) is
106105
-- Part 1
107106
108107
procedure Increment_X;
109108
end Controller;
110109
111-
type Enclosing is tagged limited record
110+
type Device is tagged limited record
112111
X : Integer; -- arbitrary type
113112
114-
C : Controller (Instance => ...);
113+
C : Controller (Encloser => ...);
115114
-- Part 2, not fully shown yet
116115
end record;
117116
118117
end P;
119118
120-
The record type named :ada:`Enclosing` contains a component named :ada:`X`,
119+
The record type named :ada:`Device` contains a component named :ada:`X`,
121120
arbitrarily of type :ada:`Integer`, and another component :ada:`C` that is of
122121
protected type :ada:`Controller`. Part #1 of the solution is the access
123122
discriminant on the declaration of the protected type :ada:`Controller`:
124123

125124
.. code-block:: ada
126125
127-
protected type Controller (Instance : not null access Enclosing) is
126+
protected type Controller (Encloser : not null access Device) is
128127
129-
Given a value for the discriminant :ada:`Instance`, the code within the spec
130-
and body of type :ada:`Controller` can then reference some :ada:`Enclosing`
128+
Given a value for the discriminant :ada:`Encloser`, the code within the spec
129+
and body of type :ada:`Controller` can then reference some :ada:`Device`
131130
object via that discriminant.
132131

133-
But not just any object of type :ada:`Enclosing` will suffice. For Part #2, we
134-
must give the :ada:`Instance` discriminant a value that refers to the current
132+
But not just any object of type :ada:`Device` will suffice. For Part #2, we
133+
must give the :ada:`Encloser` discriminant a value that refers to the current
135134
instance of the record object containing this same PO object. In the package
136-
declaration above, the value passed to :ada:`Instance` is elided. The following
137-
is that code again, now showing just the declaration for :ada:`Enclosing`, but
135+
declaration above, the value passed to :ada:`Encloser` is elided. The following
136+
is that code again, now showing just the declaration for :ada:`Device`, but
138137
also including the construct that is actually passed. This is where the
139138
subtlety comes into play:
140139

141140
.. code-block:: ada
142141
143-
type Enclosing is tagged limited record
142+
type Device is tagged limited record
144143
...
145-
C : Controller (Instance => Enclosing'Access);
144+
C : Controller (Encloser => Device'Access);
146145
end record;
147146
148-
The subtlety is the expression :ada:`Enclosing'Access`. Within a type
147+
The subtlety is the expression :ada:`Device'Access`. Within a type
149148
declaration, usage of the type name denotes the current instance of that type.
150149
The current instance of a type is the object of the type that is associated
151150
with the execution that evaluates the type name. For example, during execution,
152-
when an object of type :ada:`Enclosing` is elaborated, the name
153-
:ada:`Enclosing` refers to that object.
151+
when an object of type :ada:`Device` is elaborated, the name
152+
:ada:`Device` refers to that object.
154153

155154
It isn't compiler-defined magic, the semantics are defined by the Ada standard
156155
so it is completely portable. (There are other cases for expressing the current
157156
instance of task types, protected types, and generics.)
158157

159-
Therefore, within the declaration of type :ada:`Enclosing`, the expression
160-
:ada:`Enclosing'Access` provides an access value designating the current
158+
Therefore, within the declaration of type :ada:`Device`, the expression
159+
:ada:`Device'Access` provides an access value designating the current
161160
instance of that type. This is exactly what we want and is the crux of the
162161
idiom expression. With that discriminant value, the enclosed PO spec and body
163162
can reference the other record components of the same object that contains the
@@ -174,57 +173,62 @@ value referenced in the body of procedure :ada:`Increment_X`:
174173
175174
procedure Increment_X is
176175
begin
177-
Instance.X := Instance.X + 1;
176+
Encloser.X := Encloser.X + 1;
178177
end Increment_X;
179178
180179
end Controller;
181180
182181
end P;
183182
184183
Specifically, the body of procedure :ada:`Increment_X` can use the access
185-
discriminant :ada:`Instance` to get to the current instance's :ada:`X`
186-
component. (We could express it as :ada:`Instance.all.X` but why bother.
184+
discriminant :ada:`Encloser` to get to the current instance's :ada:`X`
185+
component. (We could express it as :ada:`Encloser.all.X` but why bother.
187186
Implicit dereferencing is a wonderful thing.)
188187

189188
That's the solution. Now for some necessary details.
190189

191-
Note that we declared type :ada:`Enclosing` as a limited type, first in the
190+
Note that we declared type :ada:`Device` as a limited type, first in the
192191
visible part of the package:
193192

194193
.. code-block:: ada
195194
196-
type Enclosing is tagged limited private;
195+
type Device is tagged limited private;
197196
198197
and again in the type completion in the package private part:
199198

200199
.. code-block:: ada
201200
202-
type Enclosing is tagged limited record ... end record;
201+
type Device is tagged limited record ... end record;
203202
204-
We declare :ada:`Enclosing` as a limited type because we want to preclude
203+
We declare :ada:`Device` as a limited type because we want to preclude
205204
assignment statements for client objects of the type. Assignment of the
206-
enclosing record object would leave the PO Instance discriminant
205+
enclosing record object would leave the PO Encloser discriminant
207206
designating the prior (right-hand side) enclosing object. If the PO is
208207
written with the assumption that the enclosing object is always the one
209208
identified during creation of the PO, that assumption will no longer
210209
hold. We didn't state it up-front, but that is the assumption underlying
211-
the idiom as described.
210+
the idiom as described, and in fact, only limited types may have
211+
a component that uses the :ada:`Access` attribute in this way.
212+
Also note that any type that includes a protected or task object
213+
is limited, so a type like Device will necessarily be limited in any case.
212214

213-
The type need not be tagged for this idiom solution, but if you do make it
214-
tagged, the partial and full views must always match. That is, a tagged type
215+
The type need not be tagged for this idiom solution, but it must be
216+
limited in both its partial view and its full view. More generally, a tagged type
215217
must be limited in both views if it is limited in either view.
216218

217219
For the idiom solution to be legal, the type's completion in the private part
218-
must always be *immutably limited*, meaning that it is always truly limited.
220+
must not merely be limited, but actually *immutably limited*, meaning that it is always truly limited.
219221
There are various ways to make that happen (see
220222
:aarm22:`AARM22 7.5 (8.1/3) <7-5>` ) but the easiest way to is to include the
221223
reserved word :ada:`limited` in the type definition within the full view, as we
222-
did above. That is known as making the type *explicitly limited*.
224+
did above. That is known as making the type *explicitly limited*. It turns out
225+
having a task or protected component also makes it immutably limited, so
226+
this requirement is naturally satisfied in this use case.
223227

224228
Why does the compiler require the type to be immutably limited?
225229

226230
Recall that a (non-tagged) private type need not be limited in both views. It
227-
can be limited in the partial client view but non-limited in the private full
231+
can be limited in the partial client view but non-limited in its full
228232
view:
229233

230234
.. code-block:: ada
@@ -243,15 +247,16 @@ Clients must treat type :ada:`Q.T` as if it is limited, but :ada:`Q.T`
243247
isn't really limited because the full view defines reality. Clients simply
244248
have a more restricted view of the type than is really the case.
245249

246-
Types that are explicitly limited really are limited, and always have a view as
247-
a limited type. That's important because the type given in :ada:`type_name'Access` must be
248-
aliased for :ada:`'Access` to be meaningful and possible on the corresponding
249-
objects. But if the type's view could change between limited and not limited,
250-
it would be aliased in some contexts and not aliased in others. To prevent that
251-
complexity, the language requires the type's view to be permanently limited so
252-
that the type will be permanently aliased. An immutably limited type is
253-
permanently aliased. In practice, we're working with record types and type
254-
extensions, so just make the type definition explicitly limited and all will be
250+
Types that are immutably limited are necessarily
251+
limited in all views.
252+
That's important because the current instance of the
253+
type given in :ada:`type_name'Access` must be
254+
aliased for :ada:`'Access` to be legal. But if the type's view could change between limited and not limited,
255+
its current instance would be aliased in some contexts and not aliased in others. To prevent that
256+
complexity, the language requires the type to be immutably limited so
257+
that the current instance of the type will be aliased in every view.
258+
In practice, we're working with record types and type
259+
extensions, so just make the full type definition explicitly limited and all will be
255260
well:
256261

257262
.. code-block:: ada

0 commit comments

Comments
 (0)