diff --git a/content/courses/ada-idioms/chapters/introduction.rst b/content/courses/ada-idioms/chapters/introduction.rst index 3f42969ed..72f0652b6 100644 --- a/content/courses/ada-idioms/chapters/introduction.rst +++ b/content/courses/ada-idioms/chapters/introduction.rst @@ -1,6 +1,234 @@ :prev_state: False -.. include:: ../../global.txt - Introduction ============ + +.. include:: ../../global.txt + +This course describes how to implement selected programming idioms in the Ada +language. + +What is an idiom? Some would say that an idiom is a workaround for an +expressive deficiency in a programming language. That is not what we mean. + +For example, we have in mind solution techniques and designs that are widely +recognized as most appropriate for certain programming situations, across +multiple programming languages. For instance, *reference counting* is a +well-known approach to tracking and managing the storage for objects and is +conceptually independent of the programming language. The implementation varies +with the language, of course, but the concept is the same. Other examples might +include +:wikipedia:`Resource Acquisition Is Allocation (RAII) `, +as well as :wikipedia:`type punning ` and inheritance idioms such +as +:wikipedia:`interface inheritance ` and +:wikipedia:`implementation inheritance `. + +We also have in mind the best way in Ada to express fundamental, commonly known +concepts such as Abstract Data Types, something the Ada language directly +supports but using *building blocks* instead of a single construct. These +concepts are included because they are fundamental to good design and because +the building blocks require some explanation. + +In contrast, we also include idioms for programming situations specific to the +Ada language. These are not deficiency workarounds, but rather, +*best practices* in situations that arise given the capabilities and semantics +in the language. For example, Ada directly supports tasks (threads). There is +an idiom for how best to associate a task with an enclosing object so that the +task has visibility to the object's other components. + +Some would equate idioms with design patterns. That's not unreasonable but is +more narrow than we intend. This is not a document dedicated to describing how +to use Ada to implement various design patterns. But note that we may refer to +a design pattern to illustrate an idiom's purpose and implementation. For +example, in the idiom for controlling object creation and initialization, the +implementation approach happens to be the same as for expressing a +Singleton [1]_. Some idiom entries might even be dedicated to implementing +design patterns, but the intent is beyond just that. + +Perhaps instead of *idiom* we should have used the term *cookbook,* but +although descriptive for some entries, that term didn't completely convey the +intent either. + + +Assumptions +----------- + +We assume the reader knows Ada to some degree, including some advanced topics. +For those lacking significant familiarity, we hope these solutions will at +least give a sense for how to apply the language. We direct such readers to the +:ref:`online Learn courses dedicated to the Ada language itself `. + + +Definitions +----------- + +For the sake of avoiding duplication in the idiom entries, the following terms +are defined here. Note that the Ada Language Manual includes a glossary in +:arm22:`Section 1.3 <1-3>` (located in Annex N prior to Ada 2022). Some of the +following expand on the definitions found there. + +Suppliers and Clients +~~~~~~~~~~~~~~~~~~~~~ + +*Suppliers* are software units that provide programming entities to other +software units, the users. These users are the *clients* of the supplied units. +The concept is simple and intuitive, but by defining these terms we can convey +these roles quickly in the idioms' discussions. + +For example, a unit that defines a type and associated operations would be a +supplier. Client units could use that type to declare objects, and/or apply the +operations to such objects. The language-defined package :ada:`Ada.Text_IO` is +an example of a supplier. Similarly, the unit that defines a library, such as a +math library, is a supplier. Callers to the math library routines are the +clients. The generic package +:ada:`Ada.Numerics.Generic_Complex_Elementary_Functions`, once instantiated, +would be an example supplier. (Arguably, the generic package itself would be a +supplier to the client that instantiates it, but instantiation is the only +possibility in that narrow case. Only the routines in the instances can be +called.) + +Betrand Meyer's book on OOP [2]_ limits these terms specifically to the case of +a type used in an object declaration. Our definitions cover that case but +others as well. + +Units can be both suppliers and clients, because a given supplier's facility, +i.e., the interface and/or implementation, may be built upon the facilities +defined by other suppliers. + +Compile-time Visibility +~~~~~~~~~~~~~~~~~~~~~~~ + +In the definitions of supplier and client above, we gave an example in which a +supplier's type was used by clients to declare objects of the type. For the +client to legally do so |mdash| that is, for the compiler to accept this usage +and process the code |mdash| the use of the supplier's type has to satisfy the +scope and visibility rules of the programming language. + +Good implementations harness these visibility rules to adhere to the software +engineering principles of information hiding and abstraction, both of which +require that nothing of the implementation be made visible to clients unless +necessary. Compiler enforcement ensures rigorous adherence to those principles. + +Therefore, modern languages provide some way to express this control. For +example, in Ada, a package can have both a *public* part and a *private* part. +Clients have no compile-time visibility to the private part, nor to the package +body, as both parts contain implementation artifacts. In class-oriented +languages, parts of the class can be marked as *public,* *private*, and +*protected* (the details depend on the specific language). + +The idioms explored in +:ref:`Fundamental Packages ` +are largely variations on expressing this control in Ada. More details on the +topic are provided in those idioms. + +Views +~~~~~ + +In Ada, a *view* of an entity defines what the developer can legally do with +that entity. For example, the declaration of an object defines a view of that +object. The operations allowed by that view are determined by the type used to +declare the object: a signed integer type would allow signed integer numeric +operations, but not, say, bit-level operations, nor array indexing, and so on. +Furthermore, the view includes whether the object is a constant. + +An entity can have more than one view, depending on where in the text of the +source code a view of that entity is considered. For example, let's say that +the integer object introduced above is in fact a variable. Within the scope of +that variable, we can refer to it by that name and update the value using +assignment statements. However, if we pass that variable as the argument to a +procedure call, within that subprogram (for that call) the view specifies a +different name for the argument, i.e., the formal parameter name. Moreover, if +that formal parameter is a mode-in parameter, within that procedure body the +view of the actual parameter is as if it is a constant rather than a variable. +No assignments via the formal parameter name are allowed because the view at +that point in the text |mdash| within that procedure body |mdash| doesn't allow +them, unlike the view outside the body. + +As another example, consider a tagged type named :ada:`Parent`, and a type +derived from it via type extension, named :ada:`Child`. It is common for a +derived type to have either additional components, or additional operations, or +both. For a given object of the :ada:`Child` type, the view via type +:ada:`Child` allows the developer to refer to the extended components and/or +operations. But we can convert the :ada:`Child` object to a value of the +:ada:`Parent` type using what is known as a *view conversion*. With that +:ada:`Parent` view of the :ada:`Child` object, we can only refer to those +components and operations defined for the :ada:`Parent` type. The compiler +enforces this temporary view. + +For further details about view conversions, please refer to that +:ref:`specific section of the Advanced Ada course `. + +Views are a fundamental concept in Ada. Understanding them will greatly +facilitate understanding the rules of the language in general. + + +Partial and Full Views +~~~~~~~~~~~~~~~~~~~~~~ + +Like objects, types also can have more than one view, again determined by the +place in the program text that a view is considered. These views can be used to +apply information hiding and abstraction. + +The declaration of a private type defines a *partial view* of a type that +reveals only some of its properties: the type name, primarily, but in +particular not the type's representation. For example: + +.. code-block:: ada + + type Rotary_Encoder is private; + +Private type declarations must occur in the *public part* of a package +declaration. Anything declared there is compile-time visible to clients of the +package so the type's name is visible, and potentially some other properties as +well. Clients can therefore declare objects of the type name, for example, but +must adhere to their partial view's affect on what is compile-time visible. + +The private type's full representation must be specified within the +*private part* of that same package declaration. For example: + +.. code-block:: ada + + type Rotary_Encoder is record ... end record; + +Therefore, within that package private part and within the package body the +*full view* is available because full representation information is +compile-time visible in those regions. (Parts of child units have the full view +as well.) This view is necessary in those two regions of the package because +the representation details are required in order to implement the corresponding +operations, among other possibilities. + +Because the clients only have the partial view they do not have compile-time +visibility to the type's internal representation. Consequently, the compiler +will not allow representation-specific references or operations in client code. +The resulting benefit is that clients are independent of the type's +representation and, therefore, it can be changed without requiring coding +changes in the clients. Clients need only be recompiled in that case. + +This application of information hiding has real-world cost benefits because +changing client code can be prohibitively expensive. That's one reason why the +maintenance phase of a project is by far the most expensive phase. Another +reason is that *maintenance* is often a euphemism for new development. Either +way, change is involved. + +As a result, when defining types, developers should use private types by +default, only avoiding them when they are not appropriate. Not using them +should be an explicit design choice, a line item in code reviews. Not defining +a major abstraction as a private type should be suspect, just as using a +:c:`struct` rather than a :c:`class` in C++ should be suspect in that case. (In +C++ anything a :c:`struct` contains is compile-time visible to clients by +default.) + +For further details about type views, please refer to that +:ref:`specific section of the Advanced Ada course `. + + +Bibliography +------------ + +.. [1] Gamma, E., R. Helm, et al. (1995), pp. 127. Design Patterns: Elements of + Reusable Object-Oriented Software. Reading, MA, Addison-Wesley + Publishing Company. + +.. [2] Meyer, B. (1997), pp. 182. Object-Oriented Software Construction, + Prentice-Hall. diff --git a/content/courses/advanced-ada/parts/data_types/types.rst b/content/courses/advanced-ada/parts/data_types/types.rst index 9dc9a16fa..0e3544f04 100644 --- a/content/courses/advanced-ada/parts/data_types/types.rst +++ b/content/courses/advanced-ada/parts/data_types/types.rst @@ -2080,6 +2080,8 @@ types. However, we can still convert between them in the same way as we did in the previous code examples. +.. _Adv_Ada_View_Conversion: + View conversion ~~~~~~~~~~~~~~~