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