Ada Coding Standards and Styles

Adrian Hoe

AdrianHoe.com

2007

Revision History
Revision 1.309 June 2008
Clean up for DocBook publishing.
Revision 1.222 August 2007
Reorganize and rework.
Revision 1.119 June 2007
Converted to DocBook, plus grammatical edits.
Revision 1.022 May 2007
First ODF version.

Table of Contents

1. Introduction
2. Editors and Settings
2.1. Editors
2.2. Editor Settings
3. Code Layout
3.1. Column Width
3.2. Spacing
3.3. Position and Alignment
4. Naming Convention
4.1. Identifier Names
4.2. Loop Names
4.3. Block Names
4.4. Subprogram Names
5. Subprograms
5.1. Parameter Names
5.2. Parameter Modes
6. Use Clauses
7. Auxiliary Standards
7.1. Interface to Other Programming Languages
7.2. SQL Standards
8. Examples

1. Introduction

A good software is coded properly. The software not only does its job well, but is also easy to add to, maintain and debug. Many great software is a collaboration of many developers, located at one single locations or distributed across continents and seas. The different coding styles are very much differed from individuals taste and culture. Every developers have habitually developed unique coding style in their native environment. The codes written by one developer may seem to be unfamiliar by another developer. Inheriting or needing to maintain and make changes to the codes that require a lot of energy to decipher, will end up trawling through lines after lines of code that doesn't make its purpose clear. Multiform codes waste countless and efforts hours of developers and thwart development progress. Looking through unfamiliar codes is much easier if it is laid out well and everything is neatly commented with details that explains any complicated construct and the reasoning behind them.

The maintainable code is most talk about among those involved in software development. A coding standards is in regardless of any programming languages. This Ada Coding Standards is specifically written for the development team at organization where Ada is the primary de facto programming language used for software development.

Ada is known as an excellent design and implementation language for all kinds of systems. Its semantic and structure make the Ada source code easy to read, understand and maintain. Because Ada is designed with software engineering in mind, Ada is also an excellent documentation language. More than source code for a compiler to compile to machine executable code, the Ada source code can also contain information about the code itself to be read and understood by humans.

This ACS (Ada Coding Standards) document describes guidelines to organize the Ada source code into a clean format. Well formatted Ada code provides visual aids in displaying important details of the code, together with additional information (comments) to help reading, understanding, and maintaining.

The examples are extracted from some project sources with permission. This document is a work-in-progress.

2. Editors and Settings

There are many editors available for writing program code. Many of them have language support for Ada. These editors provide a set of useful functions to Ada developers which increase productivity in many ways. These functions include:

  • Syntax sensitive text coloring - Quickly identify keywords, identifiers, numbers, text and etc.

  • Auto indentation - Context sensitive indentation reduces keystroke and developers can concentrate better in coding without worrying about code formatting.

  • Auto case adjust - Automatically recognizes and diffrentiate keywords and lexicons from user-defined names and identifiers and automatically capitalize first character in names and identifiers.

  • Auto completion of parantheses - Helps to reduce incomplete parantheses in complex syntax.

2.1. Editors

The choice of editor is completely a sole determination of developers according to their likings. However, the use of standard editor will be of benefits because editor's preference or configuration can be shared and standardized for adhering to a uniform coding standard.

2.1.1. Emacs

Emacs is a very powerful editor and well support in the Unix environment including Linux, FreeBSD, Mac OS X and any other UNIX flavors. It is widely accepted in both university and industrial software development. It is completely customizable according to every needs and support many languages. Emacs has very good and matured version control and it works seemlessly with SCM system such as CVS and SVN. Developer can execute commands, e.g. compile or build, from within Emacs itself without having to switch to terminal or other tools. Syntax sensitive text coloring support together with auto identation, auto case adjust, and auto completion of parantheses are superb.

2.1.2. Xcode

Xcode is an IDE (Integrated Development Environment by Apple and is supported on on Mac OS X. It comes with every Mac OS X installation disks as an optional installation. Xcode is a humongous IDE supporting C/C++, Objective-C, Ruby, Python, and of course AppleScript by default. MacAda provides downloadable Ada gnat compiler which integrates with Xcode and thus Xcode is able to support development with Ada. The Ada support in Xcode is not official and usually is bleeding-edge but usually working release by MacAda volunteers.

Xcode does not have good support in auto indentation and case adjust. Its SCM support is superlative with many SCM features built into it.

2.1.3. GPS

GPS or GNAT Programming Studio is written entirely with Ada. It is a tightly integrated IDE built for Ada in mind. Its advanced features are designed specifically for GNAT Pro and Ada developers. GPS offers many advanced features including multi-language support (including Ada, C and C++) on a wide range of environment for both native and cross-development platforms including UNIX, Linux and Windows.

GPS is suited for large and complex development with many powerful and useful features including viusal comparison tools, auto generate documentation from source, remote debugging/compilation, visualization of Ada metrics and many several others. GPS is aimed at streamlining entire Ada development process from inital coding stage through testing, debugging, system integration and maintenance.

GPS provides support for configuration management through an interface to third-party Version Control Systems, and supports a variety of platforms, including Alpha Tru64, Altix Linux, MIPS-IRIX, PA-RISC HP-UX, SPARC Solaris, x86 GNU Linux, x86 Solaris, and x86 Windows.

2.2. Editor Settings

With many editors and IDEs around, developers have wide range of choices to choose. Most developers have developed a strong personal taste with their editors of choice. The first problem is the choice of editor for each individual developer. Fortunately, most editors are flexible enough to accomodate both personal choice and coding standards. The most obvious customizable option in the editors is the tabulation or identation.

2.2.1. Tabs vs Spaces

In order to make this as simple as possible, we will be using spaces, not tabs. Indent 3 spaces per indentation level and organize code into blocks. Make sure when saving source codes, all indentation are saved as spaces not tabs. A well formatted codes with proper block indentation is easier to read as in Example 1. Some editor like Emacs can automatically indent while you type to the new line.

2.2.2. Capitalization or Case Adjust

See section 4, Naming Convention for more details.

3. Code Layout

Besides proper indentation at the beginning of every lines to form a readable block, there will be good practice to format in every each lines to separate operators and semantics with proper spacing, position and alignment.

3.1. Column Width

Limit line length to 130 columns. When a line is longer than 130 characters (including spaces), have a line break at proper position, such as after a binary operator, before or after an open parantheses or in the case of passing too many variables with long name to a subprogram. See Example 2.

3.2. Spacing

There must be at least one white space on both side of ':', ":=", "=>", and all binary and unary operators. While multiple space is permitted, it is generally discouraged except to conform to other standards, such as lining things up. There must be no white space between unary operators that are symbols ("+", "-") and their operands. Put white spaces between multiple parentheses of the same type. For example, "Factor ( ( X + Y ) * Z );".

3.3. Position and Alignment

The "is" of a procedure body should be on the same line as "procedure" if that's possible; when it can't be on the same line, it must be on a line by itself, lined up with "procedure" as in Example 1.

The "return T is" of a function body should be on the same line as "function" if that's possible; when it can't be on the same line, it must be on a line by itself, lined up with "function" as in Example 3.

The "when B is" of an entry body should be on the same line as "entry" if that's possible; when it can't be on the same line, it must be on a line by itself, lined up with "entry".

The "then" of an if (or elsif) should be on the same line as "if" (or "elsif") if that's possible; when it can't be on the same line, it must be on a line by itself, lined up with "if" (or "elsif"). See Example 1 and Example 4.

4. Naming Convention

The rational is to make reserved word visually distinguishable from other elements of the program. Reserved words must be all lower-case except when used as an attribute, in which case they must have an Initial Capital Letter (George'Access; Martha'Range).

Sometimes it is difficult to think up a good and meaningful name for identifier. Try to think of a name of closest meaning. See Example 5.

4.1. Identifier Names

Do not use CamelCase or Hungarian Notation (szFoo). Use underscores to separate words. Use mixed case for all identifiers, a capital letter beginning every word separated by underscore. Consecutive upper case letters in identifiers may only be used to represent acronyms from the Official List of Acceptable Acronyms (OLAA). An acronym must be a complete word of an identifier. "Text_IO" is acceptable, whereas "BString" is not. The best practice is to construct the OLAA based on software design specification before coding.

Attributes must follow the formatting rules for identifiers above. The use of editor's auto-capitalization feature such as Ada-mode in Emacs, makes coding easier and comply to the standards.

4.2. Loop Names

Associate names with loops when they are nested and with any loop that contains an exit statement. Naming a loop helps readers to identify the associated end of the loop. This is particularly helpful when loops are broken over screen or page boundaries. A good loop name also provides explanation to the algorithm. It is sometimes difficult to think up a descriptive name for every loop. The benefit in readability and second thought outweigh the inconvenience of naming the loop.

4.3. Block Names

When there are nested blocks, it is difficult to determine which end associates with which block. It is even more difficult when the blocks are broken across screen and page boundaries. As with loop names, sometimes, it will be difficult to think up a name for every block. Again, the benefits in readability and second thought outweigh the inconvenience of naming the block.

Repeat unit names as comments after "begin", "exception", "private", "generic" and "end".

4.4. Subprogram Names

Use verb instead of noun for clarity of subprogram names. Verb indicates operation. For example, procedure Calculate_Account_Balance; and procedure Account_Balance_Calculation;. The former gives more descriptive information when used as Calculate_Account_Balance; rather Account_Balance_Calculation;. Under some circumstances, it is not necessary to use verb for subprogram names, for example, function Factorial. For more details of subprogram, parameters and parameter modes, please see Section 5 Subprograms.

5. Subprograms

Subprograms or referred as procedures and/or functions throughout this document. Since Ada is not only an implementation language, it is also a documentation language, a well-thought and meaningful subprogram names will increase readability of the program source codes. Please refer to Section 4.4 Subprogram Names for further details.

Use named notation for procedures, except where parameter names are meaningless and named notation would detract from readability (Ada.Unchecked_Deallocation for instance).

Use positional notation for the first parameter of functions. Remaining parameters may use positional or named notation, whichever makes the code clearer. "Is_Member ( Item, Set )" is clear; "Image ( X, 7 )" may not be, since 7 might be the Width or the Base parameter. "Image ( X, Width => 7 )" is better.

5.1. Parameter Names

Like identifiers, refer to Section 4.1 Identifier Names for further details.

5.2. Parameter Modes

Do not specify parameter modes for functions, but always specify them for procedures and entries. Align ":" and parameter modes when parameters are not on the same line. See Example 6.

6. Use Clauses

Avoid all unnecessary "use" of packages. There must be no "use" clauses in package specifications. In bodies, "use type" is acceptable. Acceptable "use" clauses are limited in scope (to small subprograms or block statements, Example 7), apply to 3 or more references to the package, and leave it clear where the abbreviated names are declared.

Do not "use" parent packages. Their contents are directly visible without a use clause.

7. Auxiliary Standards

Like many other applications, an Ada application in this case, may contain language elements not of Ada origin. Most notably, an interface to some external library written in C, to enable exchange of information or interface with an external program, for instance, Asterisk. There will be, most likely, some other language element embedded into Ada codes. MySQL for instance, the Ada application not only have a C interface to call MySQL C library functions, but also need to use SQL to manipulate data stored in MySQL database.

7.1. Interface to Other Programming Languages

Annex B provides specific interface and support to C, COBOL and FORTRAN. This documentation provides a general coding standard for interfacing with these languages.

7.1.1. pragma Import

When importing from libraries written in other languages, always quote the originating location of the import. It will be a good cross-reference and makes tracking back to the source easier. See Example 8.

7.2. SQL Standards

If you are developing an application with database, you will most likely to encounter explicit SQL statement in your Ada codes. It is important to distingusihed Ada keywords from SQL keywords. Use all capital letter for all SQL keywords and lower case for all SQL identifiers. Precedes database related identifiers with capitalized "DB" and capitalize all SQL keywords give instant distinction of SQL and database elements among Ada codes as in Example 9.

Since SQL is a database language and has its own lexicon and semantic, it is always a good practice to represent SQL codes in more distingusih way rather than as a string embedded in an Ada statement as it is represented in Example 9. Example 10 shows a clearer and more practical approach which has been helpful to developers to distinguish SQL statement from Ada statements and strings.

8. Examples

Example 1. Indentation using 3 spaces. good spacing and alignment

procedure Forward ( L        :        access List;
                    Position : in     Unsigned := 0 )
is
begin
   if Position = 0 then
      L.Current := L.Tail;
   else
      for N in 1 .. Position loop
         Move ( L, 1 );
         if L.Current = null then
            L.Current := L.Tail;
            exit;
         end if;
      end loop;
   end if;
end Forward;


Example 2. Line breaks at maximum column width

      Account_Balance := ( Fixed_Asset_Balance + Current_Asset_Balance + Stock_Balance + Account_Receivable_Balance ) -
                            ( Total_Liability + Total_Expenses + Future_Dated_Transaction );

      Do_Multiple_Processing ( Total_Asset_Balance_Before_Tax => Ledger_1.Total_Asset_Baance_Before_Tax,
                               Tax_Rate                       => 0.35,
                               Total_Asset_Balance_After_Tax  => Ledger_1.Total_Asset_Balance_After_Tax );


Example 3. Alignment of return with function


function Recurse_Available ( Total  : Integer;
                             I      : Integer;
                             Conf   : Integer_Array;
                             Rank   : Integer_Array;
                             Lambda : Float_Array;
                             Mu     : Float_Array;
                             Bad    : Integer )
return Long_Long_Float is
   Answer : Long_Long_Float := 0.0;
   K      : Integer;
   ...
begin
   ...
end Recurse_Available;

      


Example 4. Position and alignment of if .. then

      if Stock_Balance > 0 then
         Stock_Available := True;
      elsif Stock_Balance < 0 then
         Do_Critical_Reorder;
      else
         Replenish_Stock;
      end if;


      ...


      if Stock_Balance + Account_Receivable_Balance > Fixed_Asset_Balance + Current_Asset_Balance - Cash_In_Hand
      then
         Do_Something;
      elsif Current_Asset_Balance + Fixed_Asset_Balance + Total_Income < Total_Liability + Total_Expenses
      then
         Do_Something_Nice;
      end if;


Example 5. Indentifier names and position alignment

   type Speed is new Integer range 0 .. 300;

   Vehicle_Speed          : Speed;
   Relative_Vehicle_Speed : Speed;


Example 6. Alignments and parameter modes


procedure Dynamic_Sensor_Fusion ( N             : in     Integer;
                                  F             : in     Integer;
                                  Value         : in out Object_Type;
                                  Bounds        : in out Reading_Type;
                                  Data          : in out Reading_Type_Array;
                                  Print_Details : in     Integer;
                                  Results       :    out Result_Type )
is
   I           : Integer;
   Cardinality : Integer := 0;
   Factors     : Integer := 0;
   ...
begin
   ...
end Dynamic_Sensor_Fusion;

      


Example 7. Use clause in limted scope

   declare 
      use Stack;
   begin
      ...
      Push ( M );
      ...
      N := Pop;
      ...
   exception
      when Error  =>
         Put ( ”Stack manipulation error.” );
      when others =>
         Put ( ”Something else went wrong with Stack.” );
   end;


Example 8. Importing from a C library (MySQL)

   
   function Mysql_Kill ( Mysql : MYSQL_SERVER; Pid : C.Unsigned_Long ) return C.Int;
   pragma Import ( C, Mysql_Kill, "mysql_kill" );                                    -- mysql.h:193


Example 9. SQL statements in Ada code (MySQL)

   
   DB.Connect ( DB_Tms, "localhost", "tms" );
   DB_Qid := DB.Query ( DB_Tms, "SELECT first_name,last_name,login_name FROM users;" );


Example 10. Clearly distinguished SQL statement

   procedure Get_Employee_Record ( Employee_ID : in String; Employee_Detail :    out Employee_Record )

      Sql_Get_Employee : constant string := "select * from employee where employee_id = '" & Emplyee_ID & "';";

      Qid              : Db.Query_Id;

   begin
      Qid := Db.Query ( DB_Payroll, Sql_Get_Employee );
      ...
   end Get_Employee_Record;