Christoph Karl Walter Grein
Hier ein immer aktuelles Problem. Als ich vor einigen Jahren zum ersten Mal ein Thema für Ada Magica suchte, stieß ich darauf, und wie der Zufall es so will, ist es gerade wieder einmal virulent. Wie oft hat man sich schon darüber geärgert, dass formale out-Parameter (in Ada 83) nicht gelesen werden dürfen. Das geht im Laufe der Zeit so ins Blut über, dass man auch da Verrenkungen macht, wo es überhaupt nicht nötig ist. Drum sei es allen laut verkündet:
In Ada 95 ist dieses Ärgernis generell beseitigt. Hier dürfen out-Parameter ohne Einschränkung gelesen werden, nur gleicht Lesen vor dem Schreiben dem Lesen einer uninitialisierten Variablen.
Wir haben zum Beispiel einen Haufen von Akten verschiedenster Art (einen diskriminierten Verbund), und für alle Varianten dieses Verbundes wollen wir Werte zwischenspeichern:
package Archiv is type Schlüsselmuster is (Schreibtisch, Tresor, ...); type Akten (Schlüssel: Schlüsselmuster := Schreibtisch) is record case Schlüssel is when Schreibtisch => Vertraulich: ...; when Tresor => Geheim: ...; when ... end case; end record; procedure Schreib (Akt: in Akten); -- O wie mach ich's nur, das Lesen? -- So? procedure Lies (Akt: in out Akten); -- falscher Modus -- Oder so? procedure Lies (mit: in Schlüsselmuster; -- umständlich Akt: out Akten); end Archiv; package body Archiv is Speicher: array (Schlüsselmuster) of Akten; procedure Schreib (Akt: in Akten) is begin Speicher (Akt.Schlüssel) := Akt; end Schreib; procedure Lies (Akt: in out Akten) is begin Akt := Speicher (Akt.Schlüssel); end Lies; procedure Lies (mit: in Schlüsselmuster; Akt: out Akten) is begin Akt := Speicher (mit); end Lies; end Archiv;
Na ja, so geht's. Wenn man fragt, warum mit dem falschen Modus in out oder so umständlich mit dem Schlüsselparameter mit statt nur einfach und richtig und symmetrisch zu Schreib
procedure Lies (Akt: out Akten);
kriegt man unweigerlich zur Antwort: "Aber out-Parameter darf ich ja nicht lesen!"
Doch, man darf, zumindest gewisse Teile – für Felder sind es die Grenzen, für Verbunde ihre Diskriminanten und die Grenzen und Diskriminanten ihrer Komponenten, die gelesen werden dürfen, RM_83 6.2 (5)! Warum das so ist? Nun, wie sollte sonst jemals Folgendes funktionieren?
Text: String (20 .. 50); Text_IO.Get_Line (Text (21 .. 30), Letzter);
Jeder kennt Text_IO. Hier ist Text der aktuelle Parameter für den formalen out-Parameter Item, und im Rumpf von Get_Line geschieht etwa Folgendes:
for C in Item'Range loop Item (C) := Next_Character; end loop;
Die Attribute Item'First [21], Item'Last [30], Item'Range können zum Lesen der Grenzen verwendet werden, wobei die Werte für unser Beispiel in Klammern angegeben sind. Die Lösung für unser Schlüsselproblem lautet folglich
procedure Lies (Akt: out Akten) is -- so mach ich's richtig mit begin -- richtigem Modus und Akt := Speicher (Akt.Schlüssel); -- Lesen der Diskriminante end Lies;
und wir räumen den Tresor mit
declare Inhalt: Akten (Tresor); begin Lies (Inhalt); end;
Wenn allerdings noch nie etwas im Tresor lag, bekommen wir Constraint_Error. Was haben wir vergessen?
© Copyright 1997 C.K.W. Grein |