[Ada Information Clearinghouse]

Ada '83 Quality and Style:

Guidelines for Professional Programmers

Copyright 1989, 1991,1992 Software Productivity Consortium, Inc., Herndon, Virginia.

CHAPTER 5: Programming Practices

5.7 Visibility

As noted in Guideline 4.2, Ada's ability to enforce information hiding and separation of concerns through its visibility controlling features is one of the most important advantages of the language. Subverting these features, for example by over liberal use of the use clause, is wasteful and dangerous.

Language Ref Manual references: 8 Visibility Rules


5.7.1 The Use Clause

guideline

example

This is a modification of the example from Guideline 4.2.3. The effect of a use clause is localized.
... 
procedure Compiler is
 ... 
 package Listing_Facilities is 
 end Listing_Facilities;
 
 ... 
 package body Listing_Facilities is separate;
 
 ... 
end Compiler;
------------------------------------------------------------------------ 
with Text_IO;
separate (Compiler) 
package body Listing_Facilities is
 ...
 
 --------------------------------------------------------------------- 
 procedure New_Line_Of_Print is 
 use Text_IO; 
 begin 
 ... 
 end New_Line_Of_Print;
 
 ... 
end Listing_Facilities;

rationale

These guidelines allow you to maintain a careful balance between maintainability and readability. Excessive use of the use clause may indeed make the code read more like prose text. However, the maintainer may also need to resolve references and identify ambiguous operations. In the absence of tools to resolve these references and identify the impact of changing use clauses, fully qualified names are the best alternative.

Avoiding the use clause forces you to use fully qualified names. In large systems, there may be many library units named in with clauses. When corresponding use clauses accompany the with clauses and the simple names of the library packages are omitted (as is allowed by the use clause), references to external entities are obscured and identification of external dependencies becomes difficult.

In some situations, the benefits of the use clause are clear. The use clause can make several infix operators visible without the need for renames clauses. A standard package can be used with the obvious assumption that the reader is very familiar with those packages and that additional overloading will not be introduced.

You can minimize the scope of the use clause by placing it in the body of a package or subprogram or by encapsulating it in a block to restrict visibility.

notes

Avoiding the use clause completely can cause problems with enumeration literals, which must then be fully qualified. This problem can be solved by declaring constants with the enumeration literals as their values, except that such constants cannot be overloaded like enumeration literals.

An argument defending the use clause can be found in Rosen (1987).

automation note

There are tools that can analyze your Ada source code, resolve overloading of names, and automatically convert between the use clause or fully qualified names.

Language Ref Manual references: 3.5.1 Enumeration Types, 4.5 Operators and Expression Evaluation, 8.3 Visibility, 8.4 Use Clauses, 8.5 Renaming Declarations, C Predefined Language Environment


5.7.2 The Renames Clause

guideline

example

procedure Disk_Write (Track_Name : in Track; 
		 Item : in Data) renames 
 System_Specific.Device_Drivers.Disk_Head_Scheduler.Transmit;

rationale

If the renaming facility is abused, the code can be difficult to read. A renames clause can substitute an abbreviation for a qualifier or long package name locally. This can make code more readable yet anchor the code to the full name. However, the use of renames clauses can often be avoided or made obviously undesirable by carefully choosing names so that fully qualified names read well. The list of renaming declarations serves as a list of abbreviation definitions (see Guideline ). By renaming imported infix operators, the use clause can often be avoided. The method prescribed in the Ada Language Reference Manual (Department of Defense 1983) for renaming a type is to use a subtype (see Guideline ). Often the parts recalled from a reuse library do not have names that are as general as they could be or that match the new application's naming scheme. An interface package exporting the renamed subprograms can map to your project's nomenclature.

Language Ref Manual references: 3.3.2 Subtype Declarations, 4.5 Operators and Expression Evaluation, 8.4 Use Clauses, 8.5 Renaming Declarations


5.7.3 Overloaded Subprograms

guideline

example

function Sin (Angles : in Matrix_Of_Radians) return Matrix; 
function Sin (Angles : in Vector_Of_Radians) return Vector; 
function Sin (Angle : in Radians) return Small_Real; 
function Sin (Angle : in Degrees) return Small_Real;

rationale

Excessive overloading can be confusing to maintainers (Nissen and Wallis 1984, 65). There is also the danger of hiding declarations if overloading becomes habitual. Attempts to overload an operation may actually hide the original operation if the parameter profile is not distinct. From that point on, it is not clear whether invoking the new operation is what the programmer intended or whether the programmer intended to invoke the hidden operation and accidentally hid it.

note

This guideline does not prohibit subprograms with identical names declared in different packages.

Language Ref Manual references: 6.6 Parameter and Result Type Profile - Overloading of Subprograms, 8.3 Visibility


5.7.4 Overloaded Operators

guideline

example

function "+" (X : in Matrix; 
	 Y : in Matrix) 
 return Matrix;
 
... 
Sum := A + B;

rationale

Subverting the conventional interpretation of operators leads to confusing code.

note

There are potential problems with any overloading. For example, if there are several versions of the "+" operator, and a change to one of them affects the number or order of its parameters, locating the occurrences that must be changed can be difficult.

Language Ref Manual references: 4.5 Operators and Expression Evaluation, 4.5.3 Binary Adding Operators


5.7.5 Overloading the Equality Operator

guideline

rationale

The predefined equality operation provided with private types is dependent on the data structure chosen to implement that type. If access types are used, then equality will mean the operands have the same pointer value. If discrete types are used, then equality will mean the operands have the same value. If a floating point type is used, then equality is based on Ada model intervals (see Guideline 7.2.8.).

Any assumptions about the meaning of equality for private types will create a dependency on the implementation of that type. See Gonzalez (1992) for a detailed discussion.

For limited private types, the definition of "=" is optional. When provided, however, there is a conventional algebraic meaning implied by this symbol. As described in Baker (1991), the following properties should remain true for the equality operator:

-reflexive: a = a
-symmetric: a = b ==> b = a
-transitive: a = b and b = c ==> a = c
Language Ref Manual references: 4.5.2 Relational Operators and Membership Tests, 6.7 Overloading of Operators, 7.4.4 Limited Types
Back to document index

AltStyle によって変換されたページ (->オリジナル) /