33 O-O programming and Ada the nineteeeventies,advances in progming methodologybrought about anw generation of languages combining the control structures of Algol 60 and the data structuring constructs of Algol W and Pascal with better system structuring facilities and support for information hiding.Although their precise traits differ,these languages share a common spirit and may be collectively called the encapsulation languages.(They are also known in the literature as"object-based",a terminology that will be discussed in the next chapter.) Although a complete list of encapsulation languages would be long,only a few have developed a sizable user community.Five deserve particular attention:Modula-2,a successor to Pascal designed at the Swiss Federal Institute of Technology by Niklaus Wirth,creator of Algol W,Pascal itselfand(later)Oberon;CLU,developed at MIT under the direction of Barbara Liskov,which comes closest to realizing object-oriented concepts but lacks inheritance;Mesa,a Xerox effort with particular emphasis on describing inter- module relationships of large systems;Alphard,by Mary Shaw,William Wulf and Ralph London of Carnegie-Mellon University,which included an assertion mechanism;and Ada We will limit our study of how to approach O-O techniques in encapsulation languages to Ada,which,besides having attracted the most attention,is also the most complete(and complex)ofthese languages,embody ing in some form most of the features found in the others.Modula-2,for example,does not offer genericity or overloading. 33.1 A BIT OF CONTEXT Ada was a response to a crisis perceived in the mid-seventies by the software policy- makers ofthe US Department of Defense(DoD).They noted in particular that the various branches of the military were using more than 450 programming languages,many of them technically obsolete,gravely hampering contractor management,programmer training, technical progress,software quality and cost control Bearing in mind the successful precedent of COBOL (the result,in the late fifties,of a DoD call for a COmmon Business-Oriented Language),they put out successive versions of a Request For Proposals for a modern software engineering language capable of supporting embedded real-time applications.A first winnowing out of the several dozen initial responses led to four candidate designs,sealed and color-coded for fairness.The field was narrowed down to two,finally leading in 1979 to the selection of the Green language designed by Jean D.Ichbiah and his group at CII-Honeywell Bull in France
33 O-O programming and Ada In the nineteen-seventies, advances in programming methodology brought about a new generation of languages combining the control structures of Algol 60 and the data structuring constructs of Algol W and Pascal with better system structuring facilities and support for information hiding. Although their precise traits differ, these languages share a common spirit and may be collectively called the encapsulation languages. (They are also known in the literature as “object-based”, a terminology that will be discussed in the next chapter.) Although a complete list of encapsulation languages would be long, only a few have developed a sizable user community. Five deserve particular attention: Modula-2, a successor to Pascal designed at the Swiss Federal Institute of Technology by Niklaus Wirth, creator of Algol W, Pascal itself and (later) Oberon; CLU, developed at MIT under the direction of Barbara Liskov, which comes closest to realizing object-oriented concepts but lacks inheritance; Mesa, a Xerox effort with particular emphasis on describing intermodule relationships of large systems; Alphard, by Mary Shaw, William Wulf and Ralph London of Carnegie-Mellon University, which included an assertion mechanism; and Ada. We will limit our study of how to approach O-O techniques in encapsulation languages to Ada, which, besides having attracted the most attention, is also the most complete (and complex) of these languages, embodying in some form most of the features found in the others. Modula-2, for example, does not offer genericity or overloading. 33.1 A BIT OF CONTEXT Ada was a response to a crisis perceived in the mid-seventies by the software policymakers of the US Department of Defense (DoD). They noted in particular that the various branches of the military were using more than 450 programming languages, many of them technically obsolete, gravely hampering contractor management, programmer training, technical progress, software quality and cost control. Bearing in mind the successful precedent of COBOL (the result, in the late fifties, of a DoD call for a COmmon Business-Oriented Language), they put out successive versions of a Request For Proposals for a modern software engineering language capable of supporting embedded real-time applications. A first winnowing out of the several dozen initial responses led to four candidate designs, sealed and color-coded for fairness. The field was narrowed down to two, finally leading in 1979 to the selection of the Green language designed by Jean D. Ichbiah and his group at CII-Honeywell Bull in France
1080 O-O PROGRAMMING AND ADA $33.1 (today's Bull).Following a few years'experience with the first industrial implementations,the language was revised and made into an ANSI standard in 1983. Ada (as Green was renamed)began a new era in language design.Never before had a language be subjected to such intense examination before being released.Never before (in spite of some valiant efforts by the PL/I team)had a language been treated like a large- scale engineering project.Working groups comprising the best experts in many countries spent weeks reviewing the proposals and contributed-in those pre-Internet days- reams of comments.Like Algol 60 a generation earlier,Ada redefined not just the language landscape but the very notion of language design. A recent revision of Ada has yielded a new language,now officially called Ada 95, which will be described at the end of this chapter.In the rest of the discussion,as elsewhere in this book,the name Ada without further qualification refers to the preceding version,Ada 83,by far the most widely used today. Has Ada been successful?Yes and no.The DoD got what it had commissioned: thanks to a rigorous implementation of the"Ada mandate",Ada became in a few years the dominant technical language in the various branches of the US military,and of the military establishment of some other countries too.It has also achieved significant use in such non- military government agencies as NASA and the European Space Agency.But except for some inroads in computing science education-aided in part by DoD incentives-the language has only had limited success in the rest of the software world.It would probably have spread more widely were it not for the competition of the very ideas described in this book:object technology,which burst into the scene just as Ada and the industry were becoming ripe for each other. The careful observer of language history can detect two ironies here.The first is that the designers of Ada were well aware of O-O ideas;although this is not widely known, Ichbiah had in fact written one of the first compilers for Simula 67,the original O-O language.As he has since explained when asked why he did not submit an O-O design to the DoD,he estimated that in the competitive bidding context of Ada's genesis such a design would be considered so far offthe mainstream as to stand no chance ofacceptance. No doubt he was right;indeed one can still marvel at the audacity of the design accepted by the DoD.It would have been reasonable to expect the process to lead to something like an improvement of JOVIAL (a sixties'language for military applications);instead,all four candidate languages were based on Pascal,a language with a distinct academic flavor,and Ada embodied bold new design ideas in many areas such as exceptions, genericity and concurrency.The second irony is that the Ada mandate,meant to force DoD software projects to catch up with progress in software engineering by retiring older approaches,has also had in the ensuing years the probably unintended effect of slowing down the adoption of newer(post-Ada)technology by the military-aerospace community. The lessons of Ada remain irreplaceable,and it is a pity that many of the O-O languages of the eighties and nineties did not pay more attention to its emphasis on software engineering quality.However obvious,this comment is all the more necessary because the occasion for discussing Ada in this book is often to contrast some of its solutions with those of O-O development-as will again happen several times in this chapter.The resulting
1080 O-O PROGRAMMING AND ADA §33.1 (today’s Bull). Following a few years’ experience with the first industrial implementations, the language was revised and made into an ANSI standard in 1983. Ada (as Green was renamed) began a new era in language design. Never before had a language be subjected to such intense examination before being released. Never before (in spite of some valiant efforts by the PL/I team) had a language been treated like a largescale engineering project. Working groups comprising the best experts in many countries spent weeks reviewing the proposals and contributed — in those pre-Internet days — reams of comments. Like Algol 60 a generation earlier, Ada redefined not just the language landscape but the very notion of language design. A recent revision of Ada has yielded a new language, now officially called Ada 95, which will be described at the end of this chapter. In the rest of the discussion, as elsewhere in this book, the name Ada without further qualification refers to the preceding version, Ada 83, by far the most widely used today. Has Ada been successful? Yes and no. The DoD got what it had commissioned: thanks to a rigorous implementation of the “Ada mandate”, Ada became in a few years the dominant technical language in the various branches of the US military, and of the military establishment of some other countries too. It has also achieved significant use in such nonmilitary government agencies as NASA and the European Space Agency. But except for some inroads in computing science education — aided in part by DoD incentives — the language has only had limited success in the rest of the software world. It would probably have spread more widely were it not for the competition of the very ideas described in this book: object technology, which burst into the scene just as Ada and the industry were becoming ripe for each other. The careful observer of language history can detect two ironies here. The first is that the designers of Ada were well aware of O-O ideas; although this is not widely known, Ichbiah had in fact written one of the first compilers for Simula 67, the original O-O language. As he has since explained when asked why he did not submit an O-O design to the DoD, he estimated that in the competitive bidding context of Ada’s genesis such a design would be considered so far off the mainstream as to stand no chance of acceptance. No doubt he was right; indeed one can still marvel at the audacity of the design accepted by the DoD. It would have been reasonable to expect the process to lead to something like an improvement of JOVIAL (a sixties’ language for military applications); instead, all four candidate languages were based on Pascal, a language with a distinct academic flavor, and Ada embodied bold new design ideas in many areas such as exceptions, genericity and concurrency. The second irony is that the Ada mandate, meant to force DoD software projects to catch up with progress in software engineering by retiring older approaches, has also had in the ensuing years the probably unintended effect of slowing down the adoption of newer (post-Ada) technology by the military-aerospace community. The lessons of Ada remain irreplaceable, and it is a pity that many of the O-O languages of the eighties and nineties did not pay more attention to its emphasis on software engineering quality. However obvious, this comment is all the more necessary because the occasion for discussing Ada in this book is often to contrast some of its solutions with those of O-O development — as will again happen several times in this chapter. The resulting
$33.2 PACKAGES 1081 critiques of Ada techniques should be viewed less as reproach than as homage to the precursor against which any new solution must naturally be assessed. 33.2 PACKAGES See“Packages", Each of the encapsulation languages offers a modular construct for grouping logically page 90. related program elements.Ada calls it a package;corresponding notions are known as modules in Modula-2 and Mesa,and clusters in CLU. “Modules and A class was defined as both a structural system component-a module-and a pes”,page170. type.In contrast,a package is only a module.An earlier discussion described this difference by noting that packages are a purely syntactic notion,whereas classes also have a semantic value.Packages provide a way to distribute system elements (variables, routines ...into coherent subsystems;but they are only needed for readability and manageability of the software.The decomposition of a system into packages does not affect its semantics:one can transform a multi-package Ada system into a one-package system,producing exactly the same results,through a purely syntactical operation- removing all package boundaries,expanding generic derivations(as explained below)and resolving name clashes through renaming.Classes,for their part,are also a semantic construct:besides providing a unit of modular decomposition,a class describes the behavior of a set of run-time objects;this semantics is further enriched by polymorphism and dynamic binding. An Ada package is a free association of program elements and may be used for various purposes.Sensible uses of this notion include writing a package to gather: "Facility inherit- A set of related constants (as with facility inheritance). ance",page 832. A library of routines,for example a mathematical library. A set of variables,constants and routines describing the implementation of one abstract object,or a fixed number of abstract objects,accessible only through designated operations(as we will do in Fortran in the next chapter). An abstract data type implementation. The last use is the most interesting for this discussion.We will study it through the example of a stack package,adapted from an example in the Ada reference manual. 33.3 A STACK IMPLEMENTATION Information hiding is supported in Ada by the two-tier declaration of packages.Every package comes in two parts,officially called"specification"and"body".The former term is too strong for a construct that does not support any formal description of package semantics (in the form of assertions or similar mechanisms),so we will use the more The standard Ada term modest word“interface”. for"routine”is“"sub. program”.We keep the The interface lists the public properties of the package:exported variables,constants, former for consistency types and routines.For routines it only gives the headers,listing the formal arguments and with other chapters. their types,plus the result type for a function,as in:
§33.2 PACKAGES 1081 critiques of Ada techniques should be viewed less as reproach than as homage to the precursor against which any new solution must naturally be assessed. 33.2 PACKAGES Each of the encapsulation languages offers a modular construct for grouping logically related program elements. Ada calls it a package; corresponding notions are known as modules in Modula-2 and Mesa, and clusters in CLU. A class was defined as both a structural system component — a module — and a type. In contrast, a package is only a module. An earlier discussion described this difference by noting that packages are a purely syntactic notion, whereas classes also have a semantic value. Packages provide a way to distribute system elements (variables, routines …) into coherent subsystems; but they are only needed for readability and manageability of the software. The decomposition of a system into packages does not affect its semantics: one can transform a multi-package Ada system into a one-package system, producing exactly the same results, through a purely syntactical operation — removing all package boundaries, expanding generic derivations (as explained below) and resolving name clashes through renaming. Classes, for their part, are also a semantic construct: besides providing a unit of modular decomposition, a class describes the behavior of a set of run-time objects; this semantics is further enriched by polymorphism and dynamic binding. An Ada package is a free association of program elements and may be used for various purposes. Sensible uses of this notion include writing a package to gather: • A set of related constants (as with facility inheritance). • A library of routines, for example a mathematical library. • A set of variables, constants and routines describing the implementation of one abstract object, or a fixed number of abstract objects, accessible only through designated operations (as we will do in Fortran in the next chapter). • An abstract data type implementation. The last use is the most interesting for this discussion. We will study it through the example of a stack package, adapted from an example in the Ada reference manual. 33.3 A STACK IMPLEMENTATION Information hiding is supported in Ada by the two-tier declaration of packages. Every package comes in two parts, officially called “specification” and “body”. The former term is too strong for a construct that does not support any formal description of package semantics (in the form of assertions or similar mechanisms), so we will use the more modest word “interface”. The interface lists the public properties of the package: exported variables, constants, types and routines. For routines it only gives the headers, listing the formal arguments and their types, plus the result type for a function, as in: See “Packages”, page 90. “Modules and types”, page 170. “Facility inheritance”, page 832. The standard Ada term for “routine” is “subprogram”. We keep the former for consistency with other chapters
1082 O-O PROGRAMMING AND ADA $33.3 function item (s:STACK)return X; The body part of a package provides the routines'implementations,and adds any needed secret elements. A simple interface A first version of the interface part of a stack package may be expressed as follows.Note that the keyword package by itself introduces a package interface;the body,which will appear later,is introduced by package body package REAL STACKS is type STACK CONTENTS is array(POSITIVE range<>)of FLOAT: type STACK (capacity:POSITIVE)is record implementation:STACK CONTENTS(1..capacity). count:NATURAL :0; end record; procedure put (x:in FLOAT;s:in out STACK); procedure remove (s:in out STACK): function item (s:STACK)return FLOAT: function empty (s:STACK)return BOOLEAN: Overflow,Underflow:EXCEPTION: end REAL STACKS; This interface lists exported elements:the type STA4CK for declaring stacks,the auxiliary type STACK CONTENTS used by STACK,the four basic routines on stacks,and two exceptions.Client packages will only rely on the interface (provided their programmers have some idea of the semantics associated with the routines). This example suggests several general observations: It is surprising to see all the details of stack representation,as given by the declarations of types STACK and STACK CONTENTS,appear in what should be a pure interface.We will see shortly the reason for this problem and how to correct it. Unlike the classes of object-oriented languages,a package does not by itself define a type.Here you must separately define a type ST4CK.One consequence of this separation,for the programmer who builds a package around an abstract data type implementation,is the need to invent two different names-one for the package and one for the type.Another consequence is that the routines have one more argument than their object-oriented counterparts:here they all act on a stack s,implicit in the stack classes given in earlier chapters. A declaration may define not only the type ofan entity,but also its initial value.Here the declaration of count in type STACK prescribes an initial value of 0.It obviates
1082 O-O PROGRAMMING AND ADA §33.3 function item (s: STACK) return X; The body part of a package provides the routines’ implementations, and adds any needed secret elements. A simple interface A first version of the interface part of a stack package may be expressed as follows. Note that the keyword package by itself introduces a package interface; the body, which will appear later, is introduced by package body. package REAL_STACKS is type STACK_CONTENTS is array (POSITIVE range ) of FLOAT; type STACK (capacity: POSITIVE) is record implementation: STACK_CONTENTS (1..capacity); count: NATURAL := 0; end record; procedure put (x: in FLOAT; s: in out STACK); procedure remove (s: in out STACK); function item (s: STACK) return FLOAT; function empty (s: STACK) return BOOLEAN; Overflow, Underflow: EXCEPTION; end REAL_STACKS; This interface lists exported elements: the type STACK for declaring stacks, the auxiliary type STACK_CONTENTS used by STACK, the four basic routines on stacks, and two exceptions. Client packages will only rely on the interface (provided their programmers have some idea of the semantics associated with the routines). This example suggests several general observations: • It is surprising to see all the details of stack representation, as given by the declarations of types STACK and STACK_CONTENTS, appear in what should be a pure interface. We will see shortly the reason for this problem and how to correct it. • Unlike the classes of object-oriented languages, a package does not by itself define a type. Here you must separately define a type STACK. One consequence of this separation, for the programmer who builds a package around an abstract data type implementation, is the need to invent two different names — one for the package and one for the type. Another consequence is that the routines have one more argument than their object-oriented counterparts: here they all act on a stack s, implicit in the stack classes given in earlier chapters. • A declaration may define not only the type of an entity, but also its initial value. Here the declaration of count in type STACK prescribes an initial value of 0. It obviates
$33.3 A STACK IMPLEMENTATION 1083 the need for an explicit initialization operation corresponding to creation;this would not be the case,however,if a less straightforward initialization were required A few details of Ada are needed to understand the type declarations:POS/T/IE and NATURAL denote the subtypes of INTEGER covering positive and non-negative integers,respectively;a type specification of the form array (TYPE range<>), where <is known as the Box symbol,describes a template for array types.To derive an actual type from such a template,you choose a finite subrange of TYPE; this is done here in STACK,which uses the subrange 1..capacity of POS/TIVE. STACK is an example of a parameterized type;any declaration of an entity of type STACK must specify an actual value for capacin,as in s:STACK (1000) In Ada,every routine argument must be characterized by a mode:in,out or in out, defining the routine's rights on the corresponding actual arguments (read-only, write-only or update).In the absence of an explicit keyword,the default mode is in. Finally,the interface also specifies two exception names:Overflow and Underflow An exception is an error condition that the programmer has decided to treat separately from the normal flow of control.The interface of the package should list any exceptions that may be raised by the package's routines and propagated to clients.More on the Ada exception mechanism below. Using a package Client code using the package is based on the interface.Here is an example from some package needing a stack of real numbers: s:REAL STACKS.STACK (1000): REAL STACKS.put (3.5,s);...; if REAL STACKS.empty (s)then ... An Ada environment must be able to compile such client code even if only the interface of REAL STACKS,not its body,is available. Syntactically,note how each use of an entity from this package (where "entities" here include type names such as STA4CK as well as routine names)must repeat the name of package REAL STACKS,using dot notation.This could become tedious,hence the need for a more implicit form of qualification.If you include the directive use REAL STACKS: at the beginning of the client package,you may write the above extract more simply as s:STACK (1000). pt(3.5,s if empry (s)then
§33.3 A STACK IMPLEMENTATION 1083 the need for an explicit initialization operation corresponding to creation; this would not be the case, however, if a less straightforward initialization were required. • A few details of Ada are needed to understand the type declarations: POSITIVE and NATURAL denote the subtypes of INTEGER covering positive and non-negative integers, respectively; a type specification of the form array (TYPE range ), where <> is known as the Box symbol, describes a template for array types. To derive an actual type from such a template, you choose a finite subrange of TYPE; this is done here in STACK, which uses the subrange 1..capacity of POSITIVE. STACK is an example of a parameterized type; any declaration of an entity of type STACK must specify an actual value for capacity, as in s: STACK (1000) • In Ada, every routine argument must be characterized by a mode: in, out or in out, defining the routine’s rights on the corresponding actual arguments (read-only, write-only or update). In the absence of an explicit keyword, the default mode is in. • Finally, the interface also specifies two exception names: Overflow and Underflow. An exception is an error condition that the programmer has decided to treat separately from the normal flow of control. The interface of the package should list any exceptions that may be raised by the package’s routines and propagated to clients. More on the Ada exception mechanism below. Using a package Client code using the package is based on the interface. Here is an example from some package needing a stack of real numbers: s: REAL_STACKS ● STACK (1000); REAL_STACKS ● put (3.5, s); …; if REAL_STACKS ● empty (s) then …; An Ada environment must be able to compile such client code even if only the interface of REAL_STACKS, not its body, is available. Syntactically, note how each use of an entity from this package (where “entities” here include type names such as STACK as well as routine names) must repeat the name of package REAL_STACKS, using dot notation. This could become tedious, hence the need for a more implicit form of qualification. If you include the directive use REAL_STACKS; at the beginning of the client package, you may write the above extract more simply as s: STACK (1000); put (3.5, s); …; if empty (s) then …;
1084 O-O PROGRAMMING AND ADA $33.3 You still need the full form,however,for any entity whose name conflicts with the name of another accessible to the client package (that is to say,declared in that package itself or in another supplier listed in a use directive). Some of the Ada literature advises programmers to stay away from the use directive altogether on the grounds that it hampers clarity:an unqualified reference such as empry(s) does not immediately tell the reader what supplier empty comes from(REAL STACK.S in the example).The equivalent in the object-oriented approach,s.empty,unambiguously indicates the supplier through the type of s. A similar problem does arise in the O-O world because of inheritance:when you see a “FLATTENING THE name in a class,it may refer to a feature declared in any ancestor.But we saw a technique STRUCTURE”,page that solves this problem at least in part:the notion of flat form. 541. Implementation The body of the REAL STACKS package might be declared along the following lines. Only one routine is shown in full. package body REAL STACKS is procedure put (x:in FLOAT:s:in out REAL STACK)is begin if s.count =s.capacity then raise Overflow end if; S.coumt :S.count +1: s.implementation (count):=x; end put; procedure remove (s:in out STACK)is ..Implementation of remove... end remove; function item (s:STACK)return X is ..Implementation of item .. end item; function empty (s:STACK)return BOOLEAN is ..Implementation of empty... end empty, end REAL STACKS; Two properties apparent in this example will be developed in more detail below:the use of exceptions to handle a run-time error by raising a special condition and treating it separately;and the need for the body to repeat most of the interface information(routine headers)that already appeared in the interface. Genericity The package as given is too specific;it should be made applicable to any type,not just FLO4T.To turn it into a generic package,use the following syntax:
1084 O-O PROGRAMMING AND ADA §33.3 You still need the full form, however, for any entity whose name conflicts with the name of another accessible to the client package (that is to say, declared in that package itself or in another supplier listed in a use directive). Some of the Ada literature advises programmers to stay away from the use directive altogether on the grounds that it hampers clarity: an unqualified reference such as empty (s) does not immediately tell the reader what supplier empty comes from (REAL_STACKS in the example). The equivalent in the object-oriented approach, s● empty, unambiguously indicates the supplier through the type of s. A similar problem does arise in the O-O world because of inheritance: when you see a name in a class, it may refer to a feature declared in any ancestor. But we saw a technique that solves this problem at least in part: the notion of flat form. Implementation The body of the REAL_STACKS package might be declared along the following lines. Only one routine is shown in full. package body REAL_STACKS is procedure put (x: in FLOAT; s: in out REAL_STACK) is begin if s ● count = s ● capacity then raise Overflow end if; s ● count := s ● count + 1; s ● implementation (count) := x; end put; procedure remove (s: in out STACK) is … Implementation of remove … end remove; function item (s: STACK) return X is … Implementation of item … end item; function empty (s: STACK) return BOOLEAN is … Implementation of empty … end empty; end REAL_STACKS; Two properties apparent in this example will be developed in more detail below: the use of exceptions to handle a run-time error by raising a special condition and treating it separately; and the need for the body to repeat most of the interface information (routine headers) that already appeared in the interface. Genericity The package as given is too specific; it should be made applicable to any type, not just FLOAT. To turn it into a generic package, use the following syntax: “FLATTENING THE STRUCTURE”, page 541
$33.4 HIDING THE REPRESENTATION:THE PRIVATE STORY 1085 generic type G is private: package STACKS is As before,replacing all occurrences of FLOAT by G... end STACKS; See appendix B. The generie clause is heavier syntax than our O-O notation for generic classes (class C [G]...)because it offers more options.In particular,the parameters declared in a generic clause may represent not just types but also routines.The appendix on genericity vs.inheritance will discuss these possibilities. The generic clause is not repeated in the package body,which will be identical to the version given earlier,except for the substitution of G for FLO47 throughout. The is private specification directs the rest of the package to treat G as a private type. This means that entities of the type may only be used in operations applicable to all Ada types:use as source or target of an assignment,as operand of an equality test,as actual argument in a routine,and a few other special operations.This is close to the convention used for unconstrained formal generic parameters in our notation.In Ada,other possibilities are also available.In particular,you can restrict the operations further by declaring the parameter as limited private,which essentially bars all uses other than as actual argument to a routine. Although called a package,a generically parameterized module such as STACKS is really a package template,since clients cannot use it directly;they must derive an actual package from it by providing actual generic parameters.We may define a new version of our stack-of-reals package through such a generic derivation: package REAL STACKS I is new STACKS(FLOAT) Generic derivation is the principal Ada mechanism for adapting modules.It is somewhat inflexible,since you can only choose between generic modules(parameterized, but not directly usable)or usable modules (not extendible any more).In contrast, inheritance allows arbitrary extensions to existing modules,according to the Open-Closed principle.Appendix B pursues the comparison further. 33.4 HIDING THE REPRESENTATION:THE PRIVATE STORY Package STACKS,as given,fails to implement the principle of information hiding:the declarations of types STACK and STACK CONTENTS are in the interface,allowing clients to access the representation of stacks directly.For example,a client might include code of the form use REAL_STACKS_1;... s:STACK,… s.implementation (3):=7.0.s.last :51;
§33.4 HIDING THE REPRESENTATION: THE PRIVATE STORY 1085 generic type G is private; package STACKS is … As before, replacing all occurrences of FLOAT by G … end STACKS; The generic clause is heavier syntax than our O-O notation for generic classes (class C [G]…) because it offers more options. In particular, the parameters declared in a generic clause may represent not just types but also routines. The appendix on genericity vs. inheritance will discuss these possibilities. The generic clause is not repeated in the package body, which will be identical to the version given earlier, except for the substitution of G for FLOAT throughout. The is private specification directs the rest of the package to treat G as a private type. This means that entities of the type may only be used in operations applicable to all Ada types: use as source or target of an assignment, as operand of an equality test, as actual argument in a routine, and a few other special operations. This is close to the convention used for unconstrained formal generic parameters in our notation. In Ada, other possibilities are also available. In particular, you can restrict the operations further by declaring the parameter as limited private, which essentially bars all uses other than as actual argument to a routine. Although called a package, a generically parameterized module such as STACKS is really a package template, since clients cannot use it directly; they must derive an actual package from it by providing actual generic parameters. We may define a new version of our stack-of-reals package through such a generic derivation: package REAL_STACKS_1 is new STACKS (FLOAT); Generic derivation is the principal Ada mechanism for adapting modules. It is somewhat inflexible, since you can only choose between generic modules (parameterized, but not directly usable) or usable modules (not extendible any more). In contrast, inheritance allows arbitrary extensions to existing modules, according to the Open-Closed principle. Appendix B pursues the comparison further. 33.4 HIDING THE REPRESENTATION: THE PRIVATE STORY Package STACKS, as given, fails to implement the principle of information hiding: the declarations of types STACK and STACK_CONTENTS are in the interface, allowing clients to access the representation of stacks directly. For example, a client might include code of the form [1] use REAL_STACKS_1;… s: STACK; … s ● implementation (3) := 7.0; s ● last := 51; See appendix B
1086 O-O PROGRAMMING AND ADA $33.4 grossly violating the underlying abstract data type specification. Conceptually,the type declarations belong in the body.Why did we not put them there in the first place?The explanation requires that we look,beyond the language,at programming environment issues. One requirement on the Ada design,already mentioned,was that it should be possible to compile packages separately and,moreover,to compile a client of any package A as soon as you have access to the interface of 4,but not necessarily to its body.This favors top-down design:to proceed with the work on a module,it suffices to know the specification of the facilities it needs;actual implementations may be provided only later. So if you have access to the interface of REAL STACKS (that is to say,the interface of STACKS,of which REAL STACKS is just a generic derivation)you must be able to compile one of its clients.Such a client will contain declarations of the form use REAL STACKS 1;... s1,s2:STACK,… s2:=s: which the poor compiler cannot properly handle unless it knows what size is taken up by an object of type STACK.But that can only be determined from the type declarations for STACK and the auxiliary type STACK CONTENTS. Hence the dilemma that faced the designers of Ada:conceptually,such declarations belong to the inferno-the body;but implementation concerns seem to require their inclusion in the paradise-the interface. The solution retained was to create a purgatory:a special section of the package that is physically tied to the interface,and compiled with it,but marked in such a way that clients may not refer to its elements.The purgatory section is called the private part of the interface;it is introduced by the keyword private (also used,as we saw above,as a qualifier for protected types).Any declaration appearing in the private part is unavailable to clients.This scheme is illustrated by our final version of the stack package interface: generic type G is private; package STACKS is type STACK(capacity:POSITIVE)is private; procedure put (x:in G;s:in out STACK); procedure remove (s:in out STACK): function item (s:STACK)return G; function empty (s:STACK)return BOOLEAN; Overflow,Underflow:EXCEPTION:
1086 O-O PROGRAMMING AND ADA §33.4 grossly violating the underlying abstract data type specification. Conceptually, the type declarations belong in the body. Why did we not put them there in the first place? The explanation requires that we look, beyond the language, at programming environment issues. One requirement on the Ada design, already mentioned, was that it should be possible to compile packages separately and, moreover, to compile a client of any package A as soon as you have access to the interface of A, but not necessarily to its body. This favors top-down design: to proceed with the work on a module, it suffices to know the specification of the facilities it needs; actual implementations may be provided only later. So if you have access to the interface of REAL_STACKS_1 (that is to say, the interface of STACKS, of which REAL_STACKS_1 is just a generic derivation) you must be able to compile one of its clients. Such a client will contain declarations of the form use REAL_STACKS_1;… s1, s2: STACK; … s2 := s1; which the poor compiler cannot properly handle unless it knows what size is taken up by an object of type STACK. But that can only be determined from the type declarations for STACK and the auxiliary type STACK_CONTENTS. Hence the dilemma that faced the designers of Ada: conceptually, such declarations belong to the inferno — the body; but implementation concerns seem to require their inclusion in the paradise — the interface. The solution retained was to create a purgatory: a special section of the package that is physically tied to the interface, and compiled with it, but marked in such a way that clients may not refer to its elements. The purgatory section is called the private part of the interface; it is introduced by the keyword private (also used, as we saw above, as a qualifier for protected types). Any declaration appearing in the private part is unavailable to clients. This scheme is illustrated by our final version of the stack package interface: generic type G is private; package STACKS is type STACK (capacity: POSITIVE) is private; procedure put (x: in G; s: in out STACK); procedure remove (s: in out STACK); function item (s: STACK) return G; function empty (s: STACK) return BOOLEAN; Overflow, Underflow: EXCEPTION;
$33.4 HIDING THE REPRESENTATION:THE PRIVATE STORY 1087 private type STACK_VALUES is array (POSITIVE range <>of G; type STACK (capacity:POSITIVE)is record implementation:STACK VALUES (1..capacity), count:NATURAL:=0; end record end STACKS; Note how type STACK must now be declared twice:first in the non-private part of the interface,where it is only specified as private;then again in the private part,where the full description is given.Without the first declaration,a line of the form s:REAL STACK would not be legal in a client,since clients only have access to entities declared in the non-private part.This first declaration only specifies the type as private,barring clients from accessing any property of stack objects other than universal operations such as assignment,equality test and use as actual argument.This is consistent with the discussion of information hiding. Type STACK VALUES is purely internal,and irrelevant to clients:so it need only be declared in the package body. [1]was onpage 1085 Make sure to understand that the information in the private part should really be in the package body,and only appears in the package specification for reasons of language implementation.With the new form of STACKS client code such as [1],which directly accessed the representation in a client,becomes invalid. See“common mis- Authors of clients modules can see the internal structure of STACK instances,but nderstanding”dis they cannot take advantage of it in their modules.This can be tantalizing (although one cussed on page 52. may imagine that a good Ada environment could hide this part from a client author requesting interface information about the class,in the manner ofthe short tool ofearlier chapters).While surprising to newcomers,the policy does not contradict the rule of information hiding:as was pointed out during the discussion of that rule,the goal is not physically to prevent client authors from reading about the hidden details,but to prevent them from using these details. Someone who would like to make things sound very complicated could summarize by the following two sentences (to be spoken very quickly to impress friend and foe):The private section of the public part ofa package lists the implementation ofthose conceptually private types which must be declared in the public part although their implementation is not publicly available.In the non-private part,these types are declared private
§33.4 HIDING THE REPRESENTATION: THE PRIVATE STORY 1087 private type STACK_VALUES is array (POSITIVE range <>) of G; type STACK (capacity: POSITIVE) is record implementation: STACK_VALUES (1..capacity); count: NATURAL := 0; end record end STACKS; Note how type STACK must now be declared twice: first in the non-private part of the interface, where it is only specified as private; then again in the private part, where the full description is given. Without the first declaration, a line of the form s: REAL_ STACK would not be legal in a client, since clients only have access to entities declared in the non-private part. This first declaration only specifies the type as private, barring clients from accessing any property of stack objects other than universal operations such as assignment, equality test and use as actual argument. This is consistent with the discussion of information hiding. Type STACK_VALUES is purely internal, and irrelevant to clients: so it need only be declared in the package body. Make sure to understand that the information in the private part should really be in the package body, and only appears in the package specification for reasons of language implementation. With the new form of STACKS client code such as [1], which directly accessed the representation in a client, becomes invalid. Authors of clients modules can see the internal structure of STACK instances, but they cannot take advantage of it in their modules. This can be tantalizing (although one may imagine that a good Ada environment could hide this part from a client author requesting interface information about the class, in the manner of the short tool of earlier chapters). While surprising to newcomers, the policy does not contradict the rule of information hiding: as was pointed out during the discussion of that rule, the goal is not physically to prevent client authors from reading about the hidden details, but to prevent them from using these details. Someone who would like to make things sound very complicated could summarize by the following two sentences (to be spoken very quickly to impress friend and foe): The private section of the public part of a package lists the implementation of those conceptually private types which must be declared in the public part although their implementation is not publicly available. In the non-private part, these types are declared private. [1] was on page 1085. See “common misunderstanding” discussed on page 52
1088 O-O PROGRAMMING AND ADA $33.5 33.5 EXCEPTIONS The STACKS generic package lists two exceptions in its interface:Overflow and Underflow.More generally,you may deal with error conditions by defining arbitrary exception names;Ada also includes predefined exceptions,triggered by the hardware or the operating system,for such cases as arithmetic overflow or exhaustion of memory. Some elements of the Ada exception mechanism were introduced in the chapter on "How not to do it- exceptions,so that we can limit ourselves to a brief examination of how exceptions fit in an Ada example". the Ada approach to software construction. page 415. Simplifying the control structure Exceptions as they exist in Ada are a technique for dealing with errors without impairing the control structure of normal processing.If a program performs a series ofactions,each of which may turn out to be impossible because of some erroneous condition,the resulting control structure may end up looking like actionl; Like others in this chapter,this exam- if errorl then ple follows Ada's error handlingl; use ofthe semicolon as an instruction else terminafor. action2; il error2 then error handling2; else action3. if error3 then error handling3; else The Ada exception mechanism is an effort to fight the complexity of such a scheme -where the elements that perform "useful"tasks sometimes look like a small archipelago in an ocean of error-handling code-by separating the handling of errors from their detection.There must still be tests to determine whether a certain erroneous condition has occurred;but the only action to take then is to raise a certain signal,the exception,which will be handled elsewhere. Raising and handling an exception To raise exceptions rather than handle errors in place,you may rewrite the extract as: actionl; if error/then raise exc/;end: action2;
1088 O-O PROGRAMMING AND ADA §33.5 33.5 EXCEPTIONS The STACKS generic package lists two exceptions in its interface: Overflow and Underflow. More generally, you may deal with error conditions by defining arbitrary exception names; Ada also includes predefined exceptions, triggered by the hardware or the operating system, for such cases as arithmetic overflow or exhaustion of memory. Some elements of the Ada exception mechanism were introduced in the chapter on exceptions, so that we can limit ourselves to a brief examination of how exceptions fit in the Ada approach to software construction. Simplifying the control structure Exceptions as they exist in Ada are a technique for dealing with errors without impairing the control structure of normal processing. If a program performs a series of actions, each of which may turn out to be impossible because of some erroneous condition, the resulting control structure may end up looking like action1; if error1 then error_handling1; else action2; if error2 then error_handling2; else action3; if error3 then error_handling3; else … The Ada exception mechanism is an effort to fight the complexity of such a scheme — where the elements that perform “useful” tasks sometimes look like a small archipelago in an ocean of error-handling code — by separating the handling of errors from their detection. There must still be tests to determine whether a certain erroneous condition has occurred; but the only action to take then is to raise a certain signal, the exception, which will be handled elsewhere. Raising and handling an exception To raise exceptions rather than handle errors in place, you may rewrite the extract as: action1; if error1 then raise exc1; end; action2; “How not to do it — an Ada example”, page 415. Like others in this chapter, this example follows Ada’s use of the semicolon as an instruction terminator