@@ -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
2827type.
2928
3029As 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 `,
121120arbitrarily of type :ada: `Integer `, and another component :ada: `C ` that is of
122121protected type :ada: `Controller `. Part #1 of the solution is the access
123122discriminant 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 `
131130object 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
135134instance 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
138137also including the construct that is actually passed. This is where the
139138subtlety 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
149148declaration, usage of the type name denotes the current instance of that type.
150149The current instance of a type is the object of the type that is associated
151150with 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
155154It isn't compiler-defined magic, the semantics are defined by the Ada standard
156155so it is completely portable. (There are other cases for expressing the current
157156instance 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
161160instance of that type. This is exactly what we want and is the crux of the
162161idiom expression. With that discriminant value, the enclosed PO spec and body
163162can 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.
187186Implicit dereferencing is a wonderful thing.)
188187
189188That'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
192191visible 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
205204assignment 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
207206designating the prior (right-hand side) enclosing object. If the PO is
208207written with the assumption that the enclosing object is always the one
209208identified during creation of the PO, that assumption will no longer
210209hold. 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
215217must be limited in both views if it is limited in either view.
216218
217219For 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.
219221There 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
221223reserved 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
224228Why does the compiler require the type to be immutably limited?
225229
226230Recall 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
228232view:
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`
243247isn't really limited because the full view defines reality. Clients simply
244248have 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
255260well:
256261
257262.. code-block :: ada
0 commit comments