Ada 2012: Neue Sprachversion verabschiedet

Die Implementierung macht nur einen geringen Teil der Softwareentwicklung aus. Mehr Zeit verschlingen Design, Code Review, Verifikation und Wartung eines Programms. Die Designer der Programmiersprache Ada haben das längst erkannt und Les- und Wartbarkeit zu wichtigen Designzielen erklärt. Mit Ada 2012 integrieren sie außerdem umfassende Prüfverfahren in die Sprache.

In Pocket speichern vorlesen Druckansicht 20 Kommentare lesen
Lesezeit: 14 Min.
Von
  • Johannes Kanig
Inhaltsverzeichnis

Die Implementierung macht nur einen geringen Teil der Softwareentwicklung aus. Mehr Zeit verschlingen Design, Code Review, Verifikation und Wartung eines Programms. Die Designer der Programmiersprache Ada haben das längst erkannt und Les- und Wartbarkeit zu wichtigen Designzielen erklärt. Mit Ada 2012 integrieren sie außerdem umfassende Prüfverfahren in die Sprache.

In der Regel verursachen Test und Wartung die höchsten Kosten in der Softwareentwicklung. Deshalb ist es erstaunlich, dass Entwickler von Programmiersprachen meistens so viel Wert auf andere Aspekte wie Design und Implementierung legen. Beispielsweise sind Kontroll- und Datenstrukturen dazu da, bestimmte Algorithmen und Features konkret zu realisieren. Je nach Programmiersprache haben Funktionen wie Klassen, Pakete oder Module die Aufgabe, eine übersichtliche Struktur des Quellcodes zu ermöglichen und Implementierungsdetails eines Teils der Software von den anderen abzuschirmen.

Einer der großen Vorteile der Programmiersprache Ada, verglichen mit den Mainstream-Sprachen, ist die hohe Wartbarkeit, gewährleistet durch die gute Lesbarkeit und eindeutige Semantik aller Programmkonstrukte – und das schon seit der ersten Version aus dem Jahre 1983. Ada verzichtet in der Syntax weitgehend auf Sonderzeichen wie &, * oder | und verwendet stattdessen Schlüsselwörter: Zeiger bekommen etwa den Zusatz access, die logischen Verknüpfungen heißen and und or anstelle && oder ||. Statt geschweifter Klammern für Blöcke gibt es ein Start-Schlüsselwort (zum Beispiel then beim If-Statement) und ein End-Schlüsselwort (etwa end if für das If-Statement). Es existiert kein Unterschied zwischen Groß- und Kleinschreibung, BufFer und buffer bezeichnen demnach das gleiche Objekt. Dadurch lassen sich Ada-Programme etwas sperriger schreiben als in anderen Sprachen, aber die Lesbarkeit wird stark erhöht, und das war schließlich das Ziel.

Zu Unrecht neigen viele Programmierer dazu, Ada als veraltet abzutun, und es herrscht die Vorstellung, dass Ada nur im amerikanischen Militär zu finden sei. Dabei ist Ada nicht älter als C++ und hat sich seitdem mit den Versionen Ada 95 und Ada 2005 konsequent weiterentwickelt. Die Sprache findet in verschiedenen Branchen Verwendung, zum Beispiel in der Luft- und Raumfahrt, im Bahnverkehr, in der Luftverkehrskontrolle und im Finanzsektor.

Mit der neuen Version Ada 2012 möchte Ada neue Anwendungsbereiche erschließen. Im Allgemeinen erlaubt Ada, den Programmieraufwand (leicht) zu erhöhen, wenn das zugunsten der Wartbarkeit, Lesbarkeit oder Verifizierbarkeit geht. Das hört bei der Syntax nicht auf, sondern geht in den semantischen Bereich über. Zum Beispiel wird die Relation zwischen einer Funktion und ihren Parametern durch Schlüsselwörter wie in (nur lesen), out (nur schreiben) oder in out (beides) dokumentiert.

Ada ist eine stark typisierte Sprache. Das heißt, dass Typkonversionen, die zu Laufzeitfehlern führen können, explizit zu schreiben sind. Die Sprache tut sich unter den Mainstream-Sprachen dadurch hervor, dass sie erlaubt, benutzerdefinierte ganzzahlige oder Gleitkommatypen einzuführen, die erstens die Absichten des Programmierers dokumentieren ("Diese Variable enthält Zahlen zwischen 1 und 100") und zweitens Laufzeitüberprüfungen einfügen, die das garantieren.

Der zuletzt angesprochene Punkt, numerische Typen mit einem bestimmten Wertebereich festzulegen, und die dazugehörigen Laufzeitüberprüfungen erleichtern die Verifizierbarkeit der Software. Wenn eine solche Überprüfung in der Testphase der Software fehlschlägt, war entweder der Wertebereich falsch gewählt oder der Code inkorrekt, in jedem Fall liegt ein Bug vor. Wichtig ist: Durch das Bereitstellen solcher Datentypen ermutigt Ada den Programmierer, über wichtige Aspekte seines Programms (hier: den Wertebereich numerischer Variablen) bei der Erstellung nachzudenken und sie durch formale Spezifikationen zu definieren.

Der folgende Quellcode zeigt ein Ada-Programm, das einen Ring-Puffer implementiert. Es wird nur die Spezifikation des Pakets gezeigt, die Implementierung ist einfach. Gegenüber einem vergleichbaren Programm in einer anderen Programmiersprache enthält es viele Informationen, die mit Typen ausgedrückt werden; es definiert drei: Content drückt aus, dass in dem Puffer nur Werte zwischen 1 und 1000 gelagert werden; Length_Type enthält alle gültigen Werte, die die Länge des Puffers (die Anzahl der gelagerten Werte) beschreiben können, also von 0 (kein Wert) bis Buf_Size (der Puffer ist voll). Schließlich gibt es Index_Type, der gültige Indizes für das Array beschreibt. Er ist Length_Type ähnlich, aber der letzte Wert Buf_Size wird ausgeschlossen, da die Indizes bei 0 anfangen.

package Ring_Buf is
-- This package defines a ring buffer, which holds even
-- integers between 1 and 1000. The semantics of the buffer
-- is "First In, First Out" (FIFO).

Buf_Size : constant Integer := 10000;
-- The maximal size of the Buffer

type Length_Type is new Integer range 0 .. Buf_Size;
-- The integer type of buffer length, it includes 0.

subtype Index_Type is Length_Type range 0 .. Length_Type'Last - 1;
-- The integer type for valid array indices.

function Even (X : Integer) return Boolean is (X mod 2 = 0);

type Content is new Integer range 1 .. 1000
with Dynamic_Predicate => (Even (Integer (Content)));


type Buf_Array is array (Index_Type) of Content;
-- The array which stores the buffer.

type Ring_Buffer is record
Data : Buf_Array;
First : Index_Type := 0;
Length : Length_Type := 0;
end record;
-- The record representing the buffer. The data itself
-- is stored in the array Data. First is the first cell
-- containing valid data. Length is the number of stored
-- items starting from First. Wrapping around the array
-- borders is possible when First + Length > Buf_Size.

function Is_Full (R : Ring_Buffer) return Boolean is
(R.Length = Length_Type'Last);
-- Check whether the buffer is full

function Is_Empty (R : Ring_Buffer) return Boolean is
(R.Length = 0);
-- Check whether the buffer is empty

procedure Clear (R : in out Ring_Buffer)
with Post => (Is_Empty (R));
-- Clear the input buffer.

function Head (R : in Ring_Buffer) return Content
with Pre => (not Is_Empty (R));
-- Return the first element of the buffer.

function Head (R : in Ring_Buffer) return Content is (R.Data (R.First));

procedure Push (R : in out Ring_Buffer; X : Content) with
Pre => (not Is_Full (R)),
Post => (not Is_Empty (R) and then R.Length = R.Length'Old + 1);

-- Push the given element X to the end of the buffer.

procedure Pop (R : in out Ring_Buffer; Element : out Content) with
Pre => (not Is_Empty (R)),
Post => (not Is_Full (R) and then
R.Length = R.Length'Old - 1 and then
Element = Head (R'Old));

function Pop (R : in out Ring_Buffer) return Content with
Pre => (not Is_Empty (R)),
Post => (not Is_Full (R) and then
R.Length = R.Length'Old - 1 and then
Pop'Result = Head (R'Old));
-- Remove the returned element from the buffer.

end Ring_Buf;

Bislang ging es nur um Features, die schon in der ersten Version der Sprache, nämlich Ada 83, vorhanden waren. Die nachfolgenden Versionen des Ada-Standards haben sich auf andere Bereiche der Sprache konzentriert. So war die große Neuerung von Ada 95 die Integration objektorientierter Programmierung, und Ada 2005 führte eine umfangreiche Container-Bibliothek ein. Mit Ada 2012 kehren die Ada-Entwickler wieder zu ihren Wurzeln zurück und wollen die Verifizierbarkeit von Ada-Software erhöhen.