Christoph Karl Walter Grein
There is a darned Ada83 rule forbidding reading formal out-parameters. You often find some contorted code to cope with this restriction - even in cases where it is absolutely unnecessary.
Suppose you have a bunch of documents (a discriminated record) you want to store. So you declare the following package:
package Archive is type Key_Template is (Desk, Safe, ...); type Document (Key: Key_Template := Desk) is record case Key is when Desk => Confidential: ...; when Safe => Secret : ...; when ... end case; end record; procedure Store (Letter: in Document); procedure Retrieve (<Parameters>); end Archive; package body Archive is Storage: array (Key_Template) of Document; procedure Store (Letter: in Document) is begin Storage (Letter.Key) := Letter; end Store; procedure Retrieve (<Parameters>) is begin ? end Retrieve; end Archive;
Now our poor programmer is brooding about how to define the retrieve operation.
procedure Retrieve (Letter: in out Document) is begin Letter := Storage (Letter.Key); end Retrieve;
which has the wrong mode in out (it's a pure out parameter), or
procedure Retrieve (use_Key: in Key_Template; Letter: out Document) is begin Letter := Storage (Use_Key); end Retrieve;
which is unnecessarily tedious because of the first parameter use_Key. Now if you ask why all these contortions instead of the simple and correct and symmetric
procedure Store (Letter: in Document); procedure Retrieve (Letter: out Document);
you will undoubtedly and invariably get the answer: "But you can't read out-parameters."
Of course you can, at least some parts - of arrays, you may read the limits, of records, you may read the discriminants and the limits and discriminants ot their components, ARM_83 6.2 (5).
Why is this so? Well, how else should the following ever work?
Text: String (20 .. 50); Text_IO.Get_Line (Text (21 .. 30), Last);
Everyone knows Text_IO. Here Text is the actual parameter for the formal out-parameter Item, and in the body of Get_Line, something like the following happens:
for C in Item'Range loop Item (C) := Next_Character; end loop;
The attributes Item'First , Item'Last , Item'Range may be used to read the limits [the values for our example are given in brackets].
Thus the solution for our key problem is
procedure Retrieve (Letter: out Document) is -- correct mode begin Letter := Storage (Letter.Key); -- read the discriminant end Retrieve;
and we empty the safe like so:
declare Contents: Document (Safe); begin Retrieve (Contents); end;
When however nothing has ever before been stored in the safe, we get Constraint_Error. Have we forgotten something?