Skip to content

Commit 03756d6

Browse files
authored
Merge pull request #1147 from AdaCore/sttaft_review
Initial editorial suggestions from T. Taft
2 parents 0116d4a + a5fc122 commit 03756d6

File tree

7 files changed

+71
-65
lines changed

7 files changed

+71
-65
lines changed

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ following:
8383
- Operations
8484

8585
The package declaration's private part and the package body may contain all
86-
the above, but one or the other (or both) will contain object declarations
86+
the above, but one or the other (or both) will contain variable declarations
8787
representing the abstraction's state.
8888

8989
Consider the following ADM version of the package :ada:`Integer_Stacks`, now
@@ -115,14 +115,14 @@ version we declare the state in the package body.
115115
end Integer_Stack;
116116
117117
Now there is no type presenting a :ada:`Stack` abstraction and the operations
118-
do not take a stack parameter because the package and its data is the instance
118+
do not take a stack parameter because the package and its data together are the instance
119119
of the abstraction. When using this idiom, there is only one stack of integers.
120120
That's why we changed the name of the package from :ada:`Integer_Stacks`, i.e.,
121121
from the plural form to the singular.
122122

123123
As with the ADT idiom, clients of an ADM can only manipulate the encapsulated
124124
state indirectly, via the visible operations. The difference is that the state
125-
to be manipulated is no longer a formal parameter. For example:
125+
to be manipulated is no longer a formal parameter of the operations. For example:
126126

127127
.. code-block:: ada
128128
@@ -138,7 +138,7 @@ type :ada:`Stack` are manipulated:
138138
-- ...
139139
Push (Answers, 42);
140140
141-
That call places the value 42 in the array :ada:`Answers.Values`, i.e., within
141+
That call places the value 42 in the (hidden) array :ada:`Answers.Values`, i.e., within
142142
the :ada:`Answers` variable. Clients can declare as many :ada:`Stack` objects
143143
as they require, each containing a distinct copy of the state defined by the
144144
type. In the ADM version, there is only one stack and therefore only one instance
@@ -170,13 +170,13 @@ The private section wasn't otherwise required when we chose to declare the data
170170
the package body.
171171

172172
The ADM idiom applies information hiding to the internal state, like the
173-
ADT idiom, except that the state is not in objects. Also, like the
173+
ADT idiom, except that the state is not in objects declared in the client. Also, like the
174174
:ref:`Groups of Related Program Units <Ada_Idioms_Groups_Of_Related_Program_Units>`,
175175
the implementations of the visible subprograms are hidden in the package body,
176176
along with any non-visible entities required for their implementation.
177177

178178
There are no constructor functions returning a value of the abstraction
179-
type because there is no such type with the ADM. However, there could be one or
179+
type because there is no such type within the ADM. However, there could be one or
180180
more initialization procedures, operating directly on the hidden state in the
181181
package private part or package body. In the :ada:`Stack` ADM there is no need
182182
because of the reasonable initial state, as is true with the ADT version.

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ client compile-time visibility to the type's representation is both an
1414
advantage and a disadvantage. Visibility to the representation makes available
1515
the expressiveness of low-level syntax, such as array indexing and aggregates,
1616
but in so doing allows client source code to be dependent on the
17-
representation. In the vast majority of cases, the resulting economic and
18-
engineering disadvantages far outweigh the expressiveness advantages.
17+
representation. In many cases, the resulting economic and
18+
engineering disadvantages of visibility on the representation will
19+
outweigh the expressiveness advantages.
1920

2021
For the sake of illustration, let's create a *stack* type that can contain
2122
values of type :ada:`Integer`. (We use type :ada:`Integer` purely for the sake
@@ -111,7 +112,7 @@ The ADT may also be abstract in the sense of object-oriented programming but
111112
that is an unrelated issue.
112113

113114
In Ada we use *private types* to define abstract data types because private
114-
types make the type's name, but not the representation, visible to clients.
115+
types make the type's name, but not its representation, visible to clients.
115116
These types are composed using syntactical building blocks: a package
116117
declaration, separated into two parts, containing a type declared in two parts,
117118
and containing declarations for subprograms to manipulate objects of the type
@@ -203,7 +204,7 @@ The full type definition is in the package private part. Therefore, for
203204
any given object of the type, the representation details |mdash| the two
204205
record components in this example |mdash| can't be referenced in client code.
205206
Clients must instead only use the operations defined by the package, passing
206-
the client objects to the formal parameters. Only the bodies of these operations
207+
the client objects as the actual parameters. Only the bodies of these operations
207208
have compile-time visibility to the representation of the :ada:`Stack`
208209
parameters, so only they can implement the functionality for those parameters.
209210

@@ -216,7 +217,7 @@ mentioned, basic operations such as assignment are allowed, unless the ADT is
216217
abstraction.
217218

218219
You may, of course, also require other ancillary type declarations in the
219-
package, either for the implementation or as additional parameters for the
220+
package, either for the implementation or as types for additional parameters for the
220221
visible operations. The array type :ada:`Content` is an example of the
221222
former case. When it is strictly an implementation artifact, as in this
222223
case, it should be in the private part so that it's hidden from clients.
@@ -279,7 +280,7 @@ There may be cases when what looks like an accessor function is provided, when
279280
in fact the function computes the return value. Similarly, there may be
280281
functions that simply return the value of a component but are part of the
281282
abstraction and happen to be implementable by returning the value of a
282-
component. For example, a real stacks ADT package would include a function
283+
component. For example, a real stack's ADT package would include a function
283284
indicating the extent of the object |mdash| that is, the number of values
284285
currently contained. In our example implementation the :ada:`Top` component happens to
285286
indicate that value, in addition to indicating the current top of the stack. The body

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

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ the type declaration itself. For procedures, that means they have formal
7070
parameters of the type. For functions, that means they either have formal
7171
parameters of the type, or return a value of the type, or both.
7272

73-
Declaration with the same package as the type itself provides the
73+
Declaration within the same package as the type itself provides the
7474
compile-time visibility to the type's representation required to
7575
implement the subprograms.
7676

@@ -136,7 +136,7 @@ Therefore, unless the extended child type is itself abstract, the type extension
136136
will be illegal. The compiler will reject the declaration of the child type,
137137
thus preventing this inappropriate constructor inheritance.
138138

139-
For an example, both for the code and the Ada rules, consider this simple
139+
For an example, both to illustrate the code and the Ada rules, consider this simple
140140
package declaration that presents the tagged private type
141141
:ada:`Graphics.Shape`:
142142

@@ -223,8 +223,7 @@ compile-time visibility that primitive operations have.
223223

224224
Therefore, the specific solution is to declare constructor functions in a
225225
separate package that is a *child* of the package declaring the tagged type.
226-
The actual term is a *hierarchical library package* but *child* conveys the
227-
concept and is less of a mouthful.
226+
This takes advantage of the *hierarchical library units* capability introduced in Ada 95.
228227

229228
Operations declared in a child package are not primitive operations for the
230229
type in the parent package, so they are not inherited when that type is
@@ -317,7 +316,8 @@ locating individual entities of interest, any decent IDE will make doing so
317316
trivial.)
318317

319318
The alternative also loses the distinction between clients that use objects of
320-
the type and clients that create those objects, because the latter will have
319+
the type and clients that create those objects, because, with the child package
320+
approach, the latter will be the only clients that have
321321
context clauses for the constructor packages.
322322

323323

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ most commonly used non-numeric type in the language. Sometimes a given type was
2424
initialization, e.g., numeric types. That wrapping approach is less common than
2525
in earlier versions of the language, given the comparatively more recent aspect
2626
:ada:`Default_Value` for scalar types, and :ada:`Default_Component_Value` for
27-
scalar components.
27+
scalar array components.
2828

2929
These facilities are often sufficient to express an abstraction's initial
3030
state. For example, we can expect that container objects will be initially

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ assignment statements. However, if we pass that variable as the argument to a
154154
procedure call, within that subprogram (for that call) the view specifies a
155155
different name for the argument, i.e., the formal parameter name. Moreover, if
156156
that formal parameter is a mode-in parameter, within that procedure body the
157-
view of the actual parameter is as if it is a constant rather than a variable.
157+
view of the actual parameter is as if it were a constant rather than a variable.
158158
No assignments via the formal parameter name are allowed because the view at
159159
that point in the text |mdash| within that procedure body |mdash| doesn't allow
160160
them, unlike the view available at the point of the call.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,12 @@ Notes
227227
-----
228228

229229
This guideline will already be used when developing a subsystem (a set of
230-
related packages in a common hierarchy) as a structuring approach during
230+
related packages in an overall hierarchy) as a structuring approach during
231231
initial development. The idiom discussed here is yet another reason to use the
232232
private part, but in this case for the sake of the future, rather than initial,
233233
development.
234234

235-
The very first version of Ada (Ada 83) did not have hierarchical packages so,
235+
The very first version of Ada (Ada 83) did not have hierarchical library units so,
236236
typically, anything not required in the private part was declared in the
237237
package body. Declaring them in the private part would only clutter the code
238238
that had to be there, without any benefit. The author's personal experience and

0 commit comments

Comments
 (0)