Ada is a modern programming language designed for large, long-lived applications – and embedded systems in particular – where reliability and efficiency are essential. It was originally developed in the early 1980s (this version is generally known as Ada 83) by a team led by Dr. Jean Ichbiah at CII-Honeywell-Bull in France. The language was revised and enhanced in an upward compatible fashion in the early 1990s, under the leadership of Mr. Tucker Taft from Intermetrics in the U.S. The resulting language, Ada 95, was the first internationally standardized (ISO) Object-Oriented Language. Under the auspices of ISO, a further (minor) revision was completed as an amendment to the standard; this version of the language is known as Ada 2005. A more significant revision was completed (including support for program annotations) and is known as Ada 2012. Another significant revision is expected to be completed in 2022.
The name “Ada” is not an acronym; it was chosen in honor of Augusta Ada Lovelace (1815-1852), a mathematician who is sometimes regarded as the world’s first programmer because of her work with Charles Babbage. She was also the daughter of the poet Lord Byron.
Ada is seeing significant usage worldwide in high-integrity / safety-critical / high-security domains including commercial and military aircraft avionics, air traffic control, railroad systems, and medical devices. With its embodiment of modern software engineering principles Ada is an excellent teaching language for both introductory and advanced computer science courses, and it has been the subject of significant university research especially in the area of real-time technologies.
Ada is multi-faceted. From one perspective it is a classical stack-based general-purpose language, not tied to any specific development methodology. It has a simple syntax, structured control statements, flexible data composition facilities, strong type checking, traditional features for code modularization (“subprograms”), and a mechanism for detecting and responding to exceptional run-time conditions (“exception handling”).
But it also includes much more:
Unlike languages based on C syntax (such as C++, Java, and C#), Ada allows the programmer to simply and explicitly specify the range of values that are permitted for variables of scalar types (integer, floating-point, fixed-point, or enumeration types). The attempted assignment of an out-of-range value causes a run-time error. The ability to specify range contraints makes programmer intent explicit and makes it easier to detect a major source of coding and user input errors.
The original Ada 83 design introduced the package construct, a feature that supports encapsulation (“information hiding”) and modularization, and that allows the developer to control the namespace that is accessible within a given compilation unit. Ada 95 introduced the concept of “child units,” adding considerably flexibility and easing the design of very large systems. Ada 2005 extended the language’s modularization facilities by allowing mutual references between package specifications, thus making it easier to interface with languages such as Java.
A key to reusable components is a mechanism for parameterizing modules with respect to data types and other program entities, for example a stack package for an arbitrary element type. Ada meets this requirement through a facility known as “generics”; since the parameterization is done at compile time, run-time performance is not penalized.
Ada 83 was object-based, allowing the partitioning of a system into modules corresponding to abstract data types or abstract objects. Full OOP support was not provided since, first, it seemed not to be required in the real-time domain that was Ada’s primary target, and, second, the apparent need for automatic garbage collection in an OO language would have interfered with predictable and efficient performance.
However, large real-time systems often have components such as GUIs that do not have real-time constraints and that could be most effectively developed using OOP features. In part for this reason, Ada 95 supplies comprehensive support for OOP, through its “tagged type” facility: classes, polymorphism, inheritance, and dynamic binding. Ada 95 does not require automatic garbage collection but rather supplies definitional features allowing the developer to supply type-specific storage reclamation operations (“finalization”). Ada 2005 provided additional OOP features including Java-like interfaces and traditional operation invocation notation.
Ada is methologically neutral and does not impose a “distributed overhead” for OOP. If an application does not need OOP, then the OOP features do not have to be used, and there is no run-time penalty.
Ada supplies a structured, high-level facility for concurrency. The unit of concurrency is a program entity known as a “task.” Tasks can communicate implicitly via shared data or explicitly via a synchronous control mechanism known as the rendezvous. A shared data item can be defined abstractly as a “protected object” (a feature introduced in Ada 95), with operations executed under mutual exclusion when invoked from multiple tasks. Asynchronous task interactions are also supported, specifically timeouts and task termination. Such asynchronous behavior is deferred during certain operations, to prevent the possibility of leaving shared data in an inconsistent state. The newest versions of Ada include lightweight mechanisms to take advantage of multicore architectures, allowing for highly efficient parallel computing, while preserving portability and remaining within the safe and well-defined Ada concurrency model.
Both in the “core” language and the Systems Programming Annex, Ada supplies the necessary features to allow the programmer to get close to the hardware. For example, you can specify the bit layout for fields in a record, define the alignment and size, place data at specific machine addresses, and express specialized or time-critical code sequences in assembly language. You can also write interrupt handlers in Ada, using the protected type facility.
Ada’s tasking features allow you to express common real-time idioms (periodic tasks, event-driven tasks), and the Real-Time Annex provides several facilities that allow you to avoid unbounded priority inversions. A protected object locking policy is defined that uses priority ceilings; this has an especially efficient implementation in Ada (mutexes are not required) since protected operations are not allowed to block. Ada 95 defined a task dispatching policy that basically requires tasks to run until blocked or preempted, and Ada 2005 introduced several others including Earliest Deadline First.
With its emphasis on sound software engineering principles Ada supports the development of high-integrity applications, including those that need to be certified against safety standards such as DO-178B and security standards such as the Common Criteria. For example, strong typing means that data intended for one purpose will not be accessed via inappropriate operations; errors such as treating pointers as integers (or vice versa) are prevented. And Ada’s array bounds checking prevents buffer overrun vulnerabilities that are common in C and C++.
However, the full language is inappropriate in a safety-critical application, since the generality and flexibility may interfere with traceability / certification requirements. Ada addresses this issue by supplying a compiler directive, pragma Restrictions, that allows you to constrain the language features to a well-defined subset (for example, excluding dynamic OOP facilities).
The evolution of Ada has seen the continued increase in support for safety-critical and high-security applications. Ada 2005 standardized the Ravenscar Profile, a collection of concurrency features that are powerful enough for real-time programming but simple enough to make certification practical. Ada 2012 introduced annotation facilities for adding pre-conditions, post-conditions, and invariants to programs. Ada 2022 extends these with additional annotations for the default initial conditions, stable properties, nonblocking, and global object usage. These can serve both for run-time checking and as input to static analysis tools.
In brief, Ada is an internationally standardized language combining object-oriented programming features, well-engineered concurrency facilities, real-time support, and built-in reliability. An appropriate tool for addressing the real issues facing software developers today, Ada is used throughout a number of major industries to design software that protects businesses and lives.