diff --git a/content/courses/ada-idioms/chapters/abstract_data_machines.rst b/content/courses/ada-idioms/chapters/abstract_data_machines.rst index 1dfa13fea..5d86fbf21 100644 --- a/content/courses/ada-idioms/chapters/abstract_data_machines.rst +++ b/content/courses/ada-idioms/chapters/abstract_data_machines.rst @@ -16,25 +16,27 @@ Motivation Solution -------- -The Abstract Data Machine (ADM) idiom is similar to the :ref:`Abstract Data -Type ` idiom in that it presents an -abstraction that doesn't already exist in the programming language. Furthermore, -like the ADT, operations are provided to manipulate the abstraction -state, which is not otherwise compile-time visible to client -code. These operations are thus enforced as the only manipulation possible, -as per the designer's intent. (The Abstract Data Machine was introduced by -Grady Booch [1]_ as the Abstract State Machine, but that name, though -appropriate, encompasses more in computer science than we intend to evoke.) - -Unlike the ADT, however, the ADM does not define the abstraction as a -type. To understand this point, recall that type declarations are -descriptions for objects that will contain data (the state). For example, our earlier -:ada:`Stack` type was defined as a record containing two components: an -array to hold the values logically contained by the :ada:`Stack` and an -integer indicating the logical top of that array. No data actually exists, -i.e., is allocated storage, until objects are declared. Clients can -declare as many objects of type :ada:`Stack` as they require and each -object has a distinct, separate copy of those two components. +The Abstract Data Machine (ADM) idiom is similar to the +:ref:`Abstract Data Type ` idiom in that it +presents an abstraction that doesn't already exist in the +programming language. Furthermore, like the ADT, operations are provided to +manipulate the abstraction state, which is not otherwise compile-time +visible to client code. These operations are thus enforced as the only +manipulation possible, as per the designer's intent. (The Abstract Data +Machine was introduced by Grady Booch [1]_ as the Abstract State Machine, but that +name, though appropriate, encompasses more in computer science than we intend +to evoke.) + +Unlike the ADT, however, the ADM does not define the abstraction as a type. To +understand this point, recall that type declarations are descriptions for +objects that will contain data (the state). For example, +our earlier :ada:`Stack` type was +defined as a record containing two components: an array to hold the values +logically contained by the :ada:`Stack` and an integer indicating the logical +top of that array. No data actually exists, i.e., is allocated storage, until +objects are declared. Clients can declare as many objects of type :ada:`Stack` +as they require and each object has a distinct, separate copy of those two +components. Clients can, of course, choose to declare only one object of a given type, in which case only one instance of the data described by the type will exist. But @@ -62,13 +64,12 @@ or even this, using an anonymously-typed array: If there is only one *stack*, these two objects will suffice. That's what the ADM does. The package, usually a library package, declares -the necessary state for a single abstraction instance. But, as an -abstraction, those data declarations must not be compile-time visible to -clients. Therefore, the state is declared in either the package private -part or the package body. Doing so requires that visible operations be -made available to clients, like any other abstraction. Hence the package is -the one instance of the abstraction, as opposed to defining one or more objects -of a type. +the necessary state for a single abstraction instance. But, as an abstraction, +those data declarations must not be compile-time visible to clients. Therefore, +the state is declared in either the package private part or the package body. +Doing so requires that visible operations be made available to clients, like any +other abstraction. Hence the package is the one instance of the abstraction, as +opposed to defining one or more objects of a type. Therefore, the package declaration's visible section contains only the following: @@ -113,11 +114,11 @@ version we declare the state in the package body. function Empty return Boolean is (Top = 0); end Integer_Stack; -Now there is no type presenting a :ada:`Stack` abstraction and the -operations do not take a stack parameter because the package and its data -is the instance of the abstraction. When using this idiom, there is only -one stack of integers. That's why we changed the name of the package from -:ada:`Integer_Stacks`, i.e., from the plural form to the singular. +Now there is no type presenting a :ada:`Stack` abstraction and the operations +do not take a stack parameter because the package and its data is the instance +of the abstraction. When using this idiom, there is only one stack of integers. +That's why we changed the name of the package from :ada:`Integer_Stacks`, i.e., +from the plural form to the singular. As with the ADT idiom, clients of an ADM can only manipulate the encapsulated state indirectly, via the visible operations. The difference is that the state @@ -137,11 +138,11 @@ type :ada:`Stack` are manipulated: -- ... Push (Answers, 42); -That call places the value 42 in the array :ada:`Answers.Values`, i.e., -within the :ada:`Answers` variable. Clients can declare as many -:ada:`Stack` objects as they require, each containing a distinct copy of -the state defined by the type. In the ADM version, there is only one stack -and therefore only one instance of the state. +That call places the value 42 in the array :ada:`Answers.Values`, i.e., within +the :ada:`Answers` variable. Clients can declare as many :ada:`Stack` objects +as they require, each containing a distinct copy of the state defined by the +type. In the ADM version, there is only one stack and therefore only one instance +of the state. Rather than declare the abstraction state in the package body, we could just as easily declare it in the package's private section: @@ -170,17 +171,15 @@ the package body. The ADM idiom applies information hiding to the internal state, like the ADT idiom, except that the state is not in objects. Also, like the -:ref:`Groups of Related Program Units -`, the implementations of the -visible subprograms are hidden in the package body, along with any -non-visible entities required for their implementation. +:ref:`Groups of Related Program Units `, +the implementations of the visible subprograms are hidden in the package body, +along with any non-visible entities required for their implementation. There are no constructor functions returning a value of the abstraction -type because there is no such type with the ADM. However, there could be -one or more initialization procedures, operating directly on the hidden -state in the package private part or package body. In the :ada:`Stack` ADM -there is no need because of the reasonable initial state, as is true with -the ADT version. +type because there is no such type with the ADM. However, there could be one or +more initialization procedures, operating directly on the hidden state in the +package private part or package body. In the :ada:`Stack` ADM there is no need +because of the reasonable initial state, as is true with the ADT version. The considerations regarding selectors/accessors are the same for the ADM as for the ADT idiom, so they are not provided by default. Also like the ADT, @@ -190,14 +189,14 @@ idiom by default. Pros ---- -In terms of abstraction and information hiding, the ADM idiom provides the -same advantages as the ADT idiom: clients have no visibility to -representation details and must use the operations declared in the package -to manipulate the state. The compiler enforces this abstract view. The ADM -also has the ADT benefit of knowing where any bugs could possibly be -located. If there is a bug in the manipulation, it must be in the one -package defining the abstraction itself. No other code would have the -compile-time visibility necessary. +In terms of abstraction and information hiding, the ADM idiom provides the same +advantages as the ADT idiom: clients have no visibility to +representation details and +must use the operations declared in the package to manipulate the state. The +compiler enforces this abstract view. The ADM also has the ADT benefit of +knowing where any bugs could possibly be located. If there is a bug in the +manipulation, it must be in the one package defining the abstraction itself. No +other code would have the compile-time visibility necessary. This idiom can be applied to any situation requiring abstraction, including hardware. For example, consider a microprocessor that has an on-board rotary diff --git a/content/courses/ada-idioms/chapters/abstract_data_types.rst b/content/courses/ada-idioms/chapters/abstract_data_types.rst index befc5c208..4075383e8 100644 --- a/content/courses/ada-idioms/chapters/abstract_data_types.rst +++ b/content/courses/ada-idioms/chapters/abstract_data_types.rst @@ -84,15 +84,15 @@ fuel injectors, the spark plugs, the steering shaft, the tie rods, and everything else |mdash| we'd certainly crash. We use abstraction in programming for the same reason. In higher-level -languages, an array is an abstraction for the combination of a base address -and offset. A file system is composed of a number of layered abstractions, -including files (at the top), then tracks, then sectors, then blocks, and -ultimately down to individual bytes. A data structure, such as a stack, a -queue, or a linked list, is an example of an abstraction, as is a valve, an -air-lock, and an engine when represented in software. Even procedures and -functions are abstractions for lower-level operations. Decomposing via abstractions -allows us to manage complexity because at any given layer we can focus on -*what* is being done, rather than how. +languages, an array is an abstraction for the combination of a base address and +offset. A file system is composed of a number of layered abstractions, +including files (at the top), then tracks, then sectors, then blocks, and ultimately +down to individual bytes. A data structure, such as a stack, a queue, or a +linked list, is an example of an abstraction, as is a valve, an air-lock, and +an engine when represented in software. Even procedures and functions are +abstractions for lower-level operations. Decomposing via abstractions allows us +to manage complexity because at any given layer we can focus on *what* is being +done, rather than how. Therefore, an abstract data type is a type that is abstract in the sense that [2]_: @@ -131,26 +131,26 @@ Therefore, an ADT package declaration may contain any of the following: If possible, you should declare at most one private type per ADT package. This keeps things simple and follows the "cohesive" principle. (Note that -the *limited-with* construct directly facilitates declaring -mutually-dependent private types that are each declared in their own -dedicated packages). However, it's not unreasonable to declare more than -one private type in the same package, especially if one of the types is -clearly the primary type and the other private type is related to the -first. For example, in defining an ADT for a maze, we could declare a -private type named :ada:`Maze` to be the primary abstraction. But mazes -have positions within them, and as clients have no business knowing how -positions are represented, both :ada:`Maze` and :ada:`Position` could -reasonably be declared as private types in the same package. +the *limited-with* construct directly +facilitates declaring mutually-dependent private types that are each declared +in their own dedicated packages). However, it's not unreasonable to +declare more than one +private type in the same package, especially if one of the types is clearly +the primary type and the other private type is related to the first. For +example, in defining an ADT for a maze, we could declare a private type named +:ada:`Maze` to be the primary abstraction. But mazes have positions within +them, and as clients have no business knowing how positions are represented, +both :ada:`Maze` and :ada:`Position` could reasonably be declared as private +types in the same package. You may use any form of private type with this idiom: basic private types, -tagged/abstract/limited private types, private type extensions, and so -forth. What's important is that the representation occurs in the private -part so that it's not compile-time visible to clients. +tagged/abstract/limited private types, private type extensions, and so forth. +What's important is that the representation occurs in the private part so that +it's not compile-time visible to clients. -The abstraction's operations consist of subprograms that each have one or -more formal parameters of the type. Clients will declare objects of the -type and pass these objects as formal parameters to manipulate those -objects. +The abstraction's operations consist of subprograms that each have one or more +formal parameters of the type. Clients will declare objects of the type and pass +these objects as formal parameters to manipulate those objects. The operations are known as *primitive operations* because they have the compile-time visibility to the private type's representation necessary to @@ -193,27 +193,27 @@ introduces the type name and ends with the keyword :ada:`private` to indicate that its representation is not provided to clients. Client code can use the type name to declare objects because the name is -visible. Likewise, clients can declare their own subprograms with -parameters of type :ada:`Stack`, or use type :ada:`Stack` as the component -type in a composite type declaration. Clients can use a private type in any -way that's consistent with the rest of the visible type declaration, except -they can't see anything representation-dependent. - -The full type definition is in the package private part. Therefore, for any -given object of the type, the representation details |mdash| the two record -components in this example |mdash| can't be referenced in client code. -Clients must instead only use the operations defined by the package, -passing the client objects to the formal parameters. Only the bodies of -these operations have compile-time visibility to the representation of the -:ada:`Stack` parameters, so only they can implement the functionality for -those parameters. +visible. Likewise, clients can declare their own subprograms with parameters +of type :ada:`Stack`, or use type :ada:`Stack` as the component type in a +composite type declaration. Clients can use a private type in any way that's +consistent with the rest of the visible type declaration, except they can't see +anything representation-dependent. + +The full type definition is in the package private part. Therefore, for +any given object of the type, the representation details |mdash| the two +record components in this example |mdash| can't be referenced in client code. +Clients must instead only use the operations defined by the package, passing +the client objects to the formal parameters. Only the bodies of these operations +have compile-time visibility to the representation of the :ada:`Stack` +parameters, so only they can implement the functionality for those parameters. Because package-defined subprograms are the only code that can access the -internals of objects of the type, the designer's intended abstract -operations are strictly enforced. They are the only manipulations that a -client can perform. As we mentioned, basic operations such as assignment -are allowed, unless the ADT is *limited* as well as private, but these -basic operations do not violate the abstraction. +internals of objects of the type, the designer's intended abstract operations +are strictly enforced. They are the only manipulations that a client can +perform. As we +mentioned, basic operations such as assignment are allowed, unless the ADT is +*limited* as well as private, but these basic operations do not violate the +abstraction. You may, of course, also require other ancillary type declarations in the package, either for the implementation or as additional parameters for the @@ -254,37 +254,36 @@ the following ADT approach: end record; end Complex_Numbers; -In the above, the function :ada:`Make` is a constructor that replaces the -use of aggregates for constructing :ada:`Complex_Number` values. Callers -pass two floating-point values to be assigned to the components of the -resulting record type. In the :ada:`Stack` ADT, a constructor for -:ada:`Stack` objects wasn't required because any stack has a known initial -state, i.e., empty, and the component default initialization is sufficient -to achieve that state. Complex numbers don't have any predeterminable state -so the constructor is required. +In the above, the function :ada:`Make` is a constructor that replaces the use +of aggregates for constructing :ada:`Complex_Number` values. Callers pass two +floating-point values to be assigned to the components of the resulting record +type. In the :ada:`Stack` ADT, a constructor for :ada:`Stack` objects wasn't +required because any stack has a known initial state, i.e., empty, and the +component default initialization is sufficient to achieve that state. Complex +numbers don't have any predeterminable state so the constructor is required. Likewise, functions :ada:`Real_Part` and :ada:`Imaginary_Part` are -selector/accessor functions that return the corresponding individual -component values of an argument of type :ada:`Complex_Number`. They are +selector/accessor functions that return the corresponding individual component +values of an argument of type :ada:`Complex_Number`. They are needed because the mathematical definition of complex numbers has those two -parts, so clients can reasonably expect to be able to get such values from -a given object. (The function names need not be distinct from the component -names, but can be if desired.) +parts, so +clients can reasonably expect to be able to get such values from a given +object. (The function names need not be distinct from the component names, but +can be if desired.) However, by default, selector/accessor functions are not included in the ADT idiom, and especially not for every component of the representation. There are no *getter* operations if you are familiar with that term. -There may be cases when what looks like an accessor function is provided, -when in fact the function computes the return value. Similarly, there may -be functions that simply return the value of a component but are part of -the abstraction and happen to be implementable by returning the value of a +There may be cases when what looks like an accessor function is provided, when +in fact the function computes the return value. Similarly, there may be +functions that simply return the value of a component but are part of the +abstraction and happen to be implementable by returning the value of a component. For example, a real stacks ADT package would include a function indicating the extent of the object |mdash| that is, the number of values -currently contained. In our example implementation the :ada:`Top` component -happens to indicate that value, in addition to indicating the current top -of the stack. The body of the :ada:`Extent` function can then be as -follows: +currently contained. In our example implementation the :ada:`Top` component happens to +indicate that value, in addition to indicating the current top of the stack. The body +of the :ada:`Extent` function can then be as follows: .. code-block:: ada @@ -297,24 +296,23 @@ as the upper bound, for the function result type.) You should not include true *getter* functions that do not meet an abstraction-defined requirement and exist purely to provide client access -to the otherwise hidden representation components included. Their usage -makes the client code dependent on the representation, just as if the -client had direct access. For the same reason, by default there are no -*setter* procedures for the representation components. Both kinds of -operations should be considered highly suspect. There's no point in hiding -the representation if these operations will make it available to clients, -albeit indirectly. +to the otherwise hidden representation components included. +Their usage makes the client code dependent +on the representation, just as if the client had direct access. For the same +reason, by default there are no *setter* procedures for the representation +components. Both kinds of operations should be considered highly suspect. +There's no point in hiding the representation if these operations will make it +available to clients, albeit indirectly. Pros ---- The advantages of an ADT are due to the strong interface presented, with -guaranteed enforcement by the compiler rather than by reliance on clients' -good behavior. The ADT designer can rely on client adherence to the -intended abstraction because client code that violates the designer's -abstraction by directly manipulating the internals of the type will not -compile; clients must call the designer's operations to manipulate the -objects. +guaranteed enforcement by the compiler rather than by reliance on clients' good +behavior. The ADT designer can rely on client adherence to the intended +abstraction because client code that violates the designer's abstraction by +directly manipulating the internals of the type will not +compile; clients must call the designer's operations to manipulate the objects. A package defining a strong interface will exhibit high cohesion, thereby aiding comprehension and consequently easing both development and @@ -338,14 +336,14 @@ change in client usage, such as performance changes, but it will not be a matter of the legality of the client code. Illegal client usage of an ADT wouldn't have compiled successfully in the first place. -The private type is the fundamental approach to creating abstractions in -Ada, just as the use of the *public*, *private*, and *protected* parts of -classes is fundamental to creating abstractions in class-oriented -languages. Not every type can be private, as illustrated by the client -expectation for array indexing in Ada prior to Ada 2012. Not every type -should be private, for example those that are explicitly numeric. But the -ADT should be the default design idiom when decomposing a problem into a -solution. +The private type is the fundamental approach to creating abstractions in Ada, +just as the use of the *public*, *private*, and *protected* parts of classes is +fundamental to creating abstractions in class-oriented languages. Not every +type can be private, as illustrated by the client expectation for array +indexing in Ada prior to Ada 2012. +Not every type should be private, for example those that are +explicitly numeric. But the ADT should be the default design idiom when +decomposing a problem into a solution. Cons ---- @@ -364,20 +362,22 @@ private types is worth the protections afforded. Relationship With Other Idioms ------------------------------ -The package-oriented idioms described here and :ref:`previously -` are the foundational -program composition idioms because packages are the primary structuring -unit in Ada. That is especially true of the :ref:`Abstract Data Type -` idiom, which is the primary type -specification facility in Ada. We will describe additional package-oriented -idioms, especially regarding hierarchical packages, but those kinds of -packages are optional. - -The basic package is not optional in Ada for a program of any significant -size or complexity. (One could have a program consisting entirely of the -main program, but either that program is relatively simple and small or it -is badly structured.) As a consequence, other idioms will exist within -packages designed using one of these idioms or some other package idiom. +The package-oriented idioms described here and +:ref:`previously ` +are the foundational program composition idioms because packages are the +primary structuring unit in Ada. That is especially true of the +:ref:`Abstract Data Type ` idiom, which is the +primary type specification facility in Ada. We will +describe additional package-oriented idioms, +especially regarding hierarchical packages, but those kinds +of packages are optional. + +The basic package is not optional in Ada for a +program of any significant size or complexity. (One could have a program +consisting entirely of the main program, but either that program is relatively +simple and small or it is badly structured.) As a consequence, other idioms +will exist within packages designed using one of these idioms or some other +package idiom. Notes diff --git a/content/courses/ada-idioms/chapters/constructor_functions_for_abstract_data_types.rst b/content/courses/ada-idioms/chapters/constructor_functions_for_abstract_data_types.rst index 0aafbf787..d0dff1523 100644 --- a/content/courses/ada-idioms/chapters/constructor_functions_for_abstract_data_types.rst +++ b/content/courses/ada-idioms/chapters/constructor_functions_for_abstract_data_types.rst @@ -65,11 +65,10 @@ functions that return an object of the type. Like any function there may be formal parameters specified, but not necessarily. Functions and procedures that manipulate objects of the private type are -*primitive operations* for the type if they are declared in the same -package as the type declaration itself. For procedures, that means they -have formal parameters of the type. For functions, that means they -either have formal parameters of the type, or return a value of the -type, or both. +*primitive operations* for the type if they are declared in the same package as +the type declaration itself. For procedures, that means they have formal +parameters of the type. For functions, that means they either have formal +parameters of the type, or return a value of the type, or both. Declaration with the same package as the type itself provides the compile-time visibility to the type's representation required to diff --git a/content/courses/ada-idioms/chapters/controlling_obj_initialization_creation.rst b/content/courses/ada-idioms/chapters/controlling_obj_initialization_creation.rst index c55927b70..fee8fef68 100644 --- a/content/courses/ada-idioms/chapters/controlling_obj_initialization_creation.rst +++ b/content/courses/ada-idioms/chapters/controlling_obj_initialization_creation.rst @@ -57,8 +57,8 @@ is an access type, the automatic default value :ada:`null` initializes ... end Binary_Trees; -In both cases, simply declaring an object in the client code is -sufficient to ensure it is initially empty. +In both cases, simply declaring an object in the client code is sufficient to +ensure it is initially empty. However, not all abstractions have a meaningful default initial state. Default initialization will not suffice to fully initialize objects in these cases, so diff --git a/content/courses/ada-idioms/chapters/essential_idioms_for_packages.rst b/content/courses/ada-idioms/chapters/essential_idioms_for_packages.rst index 818c14a09..ddd6314da 100644 --- a/content/courses/ada-idioms/chapters/essential_idioms_for_packages.rst +++ b/content/courses/ada-idioms/chapters/essential_idioms_for_packages.rst @@ -19,11 +19,11 @@ Specifically, packages should exhibit high cohesion and loose coupling related to one another, in the context of the problem being solved. Unrelated entities should not be declared in the same module. This allows the reader to focus on one primary concept, which should be the subject of -the package. Coupling is the degree to which a module depends upon other -modules. Loose coupling enhances comprehension and maintenance because it -allows readers and future developers to examine and modify the module in -relative isolation. Coupling and cohesion are interrelated: higher -cohesion tends to result in less coupling. +the package. Coupling is the degree to which a module +depends upon other modules. Loose coupling enhances comprehension and +maintenance because it allows readers and future developers to examine and modify the +module in relative isolation. Coupling and cohesion are interrelated: +higher cohesion tends to result in less coupling. Solution diff --git a/content/courses/ada-idioms/chapters/inheritance_idioms.rst b/content/courses/ada-idioms/chapters/inheritance_idioms.rst index 7ee508803..c6b869aa7 100644 --- a/content/courses/ada-idioms/chapters/inheritance_idioms.rst +++ b/content/courses/ada-idioms/chapters/inheritance_idioms.rst @@ -48,11 +48,11 @@ we express that inheritance via derived types representing the categories and subcategories. Ada's strong typing ensures they are treated as disjoint entities. -Although the derived child type is distinct from the parent type, the -child is the same *kind* as the parent type. Some authors use *kind of* -as the name for the relationship between the child and parent. Meyer -uses the term *is-a* [1]_, a popular term that we will use too. For -example, a cat *is a* mammal, and also is an animal. +Although the derived child type is distinct from the parent type, the child is +the same *kind* as the parent type. Some authors use *kind of* as the name for the +relationship between the child and parent. Meyer uses the term *is-a* [1]_, a +popular term that we will use too. For example, a cat *is a* mammal, and also is +an animal. The fundamental difference between :ref:`Subtype Inheritance ` and @@ -87,11 +87,10 @@ declarations for derived types, providing considerable flexibility and expressive power for controlling the client's view of the child and parent types. -For example, in Ada, full dynamic OOP capabilities require type -declarations to be decorated with the reserved word :ada:`tagged`. However, -from its earliest days, Ada has also supported a static form of -inheritance, using types that are not tagged. The solution we describe -below works with both forms of inheritance. +For example, in Ada, full dynamic OOP capabilities require type declarations to +be decorated with the reserved word :ada:`tagged`. However, from its earliest days, +Ada has also supported a static form of inheritance, using types that are not +tagged. The solution we describe below works with both forms of inheritance. The developer also has a choice of whether the parent type and/or the child type is a private type. Using private types is the default design choice, for the @@ -208,11 +207,12 @@ then show the two idiom expressions in separate subsections. - Whether the child type is visibly derived will vary with the :ref:`inheritance idiom ` solution. -To avoid unnecessary code duplication, we use the same parent type, -declared as a simple tagged private type, in the examples for the two idiom -solutions. The parent type could itself be derived from some other tagged -type, but that changes nothing conceptually significant. We declare parent -type in package :ada:`P` as follows: +To avoid unnecessary code duplication, we use +the same parent type, declared as a simple tagged private type, in the examples +for the two idiom solutions. The parent type +could itself be derived from some other tagged type, but that changes nothing +conceptually significant. We declare parent type in package :ada:`P` as +follows: .. code-block:: ada @@ -248,12 +248,12 @@ part of the package: type Child is new Parent with record ... end record; end Q; -The primitive operations from the parent type are implicitly declared -immediately after the private extension declaration. That means those +The primitive operations from the parent type are implicitly +declared immediately after the private extension declaration. That means those operations are in the visible part of the package, hence clients can invoke them. Any additional operations for the client interface will be explicitly -declared in the visible part as well, as will any overriding declarations -for those inherited operations that are to be changed. +declared in the visible part as well, as will any overriding declarations for +those inherited operations that are to be changed. For example, here is a basic bank account :ref:`ADT ` that we will use as the parent type @@ -466,9 +466,9 @@ For example, we might use a *controlled type* in the implementation of a tagged private type. These types have procedures :ada:`Initialize` and :ada:`Finalize` defined as primitive operations. Both are called automatically by the compiler. Clients generally don't have any business directly calling -them so we usually use implementation inheritance with controlled types. -But if clients did have the need to call them we would use Subtype Inheritance -instead, to make them visible to clients. +them so we usually use implementation inheritance with controlled types. But if +clients did have the need to call them we +would use Subtype Inheritance instead, to make them visible to clients. For example, the following is a generic package providing an abstract data type for unbounded queues. As such, the :ada:`Queue` type uses dynamic allocation diff --git a/content/courses/ada-idioms/chapters/programming_by_extension.rst b/content/courses/ada-idioms/chapters/programming_by_extension.rst index ecb393426..22346c73f 100644 --- a/content/courses/ada-idioms/chapters/programming_by_extension.rst +++ b/content/courses/ada-idioms/chapters/programming_by_extension.rst @@ -87,7 +87,7 @@ with the stack state declared in the package body: We could add the private part to the package declaration and move the state of the :ref:`ADM ` |mdash| the two variables in -this case |mdash| up there without any other changes. The subprogram bodies +this case |mdash| up there without any other changes. The subprogram bodies have the same visibility to the two variables either way. (There is no requirement for the :ada:`Content` type because :ada:`Values` is not a record component; anonymously-typed array objects are legal.) From the viewpoint of