From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,803df5f3f60558d5 X-Google-Attributes: gid103376,public From: bobduff@world.std.com (Robert A Duff) Subject: Re: Uninitialized "out" parameters Date: 1996/07/21 Message-ID: #1/1 X-Deja-AN: 169924595 references: <31EEACDA.64880EEB@sage.inel.gov> organization: The World Public Access UNIX, Brookline, MA newsgroups: comp.lang.ada Date: 1996-07-21T00:00:00+00:00 List-Id: In article <31EEACDA.64880EEB@sage.inel.gov>, Paul Whittington wrote: >In the following Ada program, should either the compiler or the run-time >get some kind of error because the out parameter is not initialized? > >procedure Testit is > > procedure SubP (op : out Integer) is > begin > op := op+1; > end SubP; > > I : Integer; > >begin > SubP (I); >end Testit; Boy, I saw a lot of misinformation in this thread. The above is legal (meaning OK at compile time), although it was illegal in Ada 83. At run time, it's a reference to an uninitialized variable. In Ada 95, such references are a bounded error. The program might raise Program_Error, or Constraint_Error on the bad reference to op. Or, it might continue executing with some value. This value may cause an exception later on. Details of exactly what can happen are in the RM (and AARM). In any case, it's not erroneous -- saying "A(I) := 3;" cannot trash random memory locations, and saying "case I is ..." cannot cause a wild jump. This is the general rule for uninitialized variables -- not a special rule about 'out' parameters. Note that the above would still be true if I were initialized to some correct value before the call. The call to SubP will de-initialize I (unless the compiler chooses to catch the error at run time). Note that the rules are different for access types, and for composites; there are certain types that cannot get de-initialized. But here, we have an integer. A friendly compiler might catch the error and raise an exception. To increase the probability of that happening, you can say "pragma Initialize_Scalars". A compiler can also give a warning about uninit vars, at compile time. But the problem is, such warnings are necessarily either overkill or underkill. (Overkill = sometimes warn about perfectly correct programs. Underkill = miss some incorrect cases.) Overkill might be acceptable if the compiler were smart enough, but separate compilation gets in the way of doing a really good job. My experience is that if warnings continually "cry wolf", then they're worse than useless. Some people pointed out that the new rule allowing reads of uninitialized variables can cause bugs. True, but the old rule can also cause bugs: procedure Get_Total(A: Some_Array; Total: out Integer) is Result: Integer := 0; begin for I in A'Range loop Result := Result + A(I); end loop; -- Oops, I forgot to say "Total := Result;". end Get_Total; Somebody pointed out that it's possible to define a language such that uninit vars are impossible. Certainly true. I've used languages like that. I found that it worked OK for local variables, but for components of records allocated in the heap, it didn't help -- it just meant that the programmer has to initialize all such components explicitly to a bogus value, which actually hides bugs, rather than preventing them. IMHO, the best solution is to have run-time checks, along with some way to suppress the checks if they turn out to be too inefficient. Pragma Initialize_Scalars *almost* does that, but it doesn't work in all cases. And it requires writing the pragma. - Bob