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.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM autolearn=unavailable autolearn_force=no version=3.4.4 X-Received: by 10.66.124.168 with SMTP id mj8mr19948038pab.32.1416839976430; Mon, 24 Nov 2014 06:39:36 -0800 (PST) X-Received: by 10.140.20.108 with SMTP id 99mr11231qgi.15.1416839976376; Mon, 24 Nov 2014 06:39:36 -0800 (PST) Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!mx02.eternal-september.org!feeder.eternal-september.org!news.glorb.com!uq10no3526444igb.0!news-out.google.com!w7ni319qay.0!nntp.google.com!s7no1544439qap.1!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Mon, 24 Nov 2014 06:39:36 -0800 (PST) In-Reply-To: Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=50.111.125.244; posting-account=Ies7ywoAAACcdHZMiIRy0M84lcJvfxwg NNTP-Posting-Host: 50.111.125.244 References: <0d8452a9-68c9-4835-b6f3-17407132ca9f@googlegroups.com> User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <8eb888f6-f37f-4754-b2e4-4987de06f350@googlegroups.com> Subject: Re: How to get nice with GNAT? From: brbarkstrom@gmail.com Injection-Date: Mon, 24 Nov 2014 14:39:36 +0000 Content-Type: text/plain; charset=ISO-8859-1 Xref: news.eternal-september.org comp.lang.ada:23692 Date: 2014-11-24T06:39:36-08:00 List-Id: On Monday, November 24, 2014 1:25:42 AM UTC-5, Jeffrey Carter wrote: > On 11/23/2014 08:05 PM, brbarkstrom wrote: > > > > I don't think you'll get a sensible response when you try to set > > Test(OK => True); or Test(OK => False) when the specification of > > the procedure Test has OK as an "out" variable. It doesn't make > > sense try to set this value as input to a variable that emerges from the procedure (Test). > > I think it's clear you have no idea what you're talking about. I set OK to True > before calling Test so that I could demonstrate that Test did not modify that value. > > > The GNAT GPL GPS tool on my Ubuntu 14.04 LTS system returns the > > two warnings: > > 7.10 warning: assignment to pass-by-copy formal may have no effect > > 7.10 warning: "raise" statement may result in abnormal return > > (RM 6.4.1(17)) > > > > In other words, a programmer shouldn't expect a variable input to > > an "out" variable in the interface specification to have any relation > > to whatever is generated in the procedure that is called. Secondly, > > an exception raised in the procedure test may result in an abnormal > > return. This is hardly a clean piece of code. > > This warning is saying that the assignment to the formal parameter OK in Test > (the "pass-by-copy formal") won't do anything because the formal is not copied > back to the actual when the procedure propagates an exception. It has nothing to > do with setting the variable OK to True. > > > When I run it, the output from the code does something that seems > > to me to be an abnormal return. It returns the output "TRUE". > > Test does not return True. OK had the value True before the call, and it still > has the value True after the call because the assignment to the formal parameter > OK in True has no effect. This is what I was trying to demonstrate. > > > procedure Test (I : in Natural; > > OK : out Boolean; > > Err_Msg : out Vstring.Bounded_String) is > > Max_I : Natural := 10; > > I_Out_Of_Range : exception; > > begin -- Test > > OK := False; > > Err_Msg := Vstring.To_Bounded_String("procedure Test was not initialized when this message was created."); > > if I <= Max_I then > > OK := True; > > Err_Msg := Vstring.To_Bounded_String("In procedure Test, I as input : "); > > Err_Msg := Vstring.Append(Err_Msg, Natural'image(I)); > > Err_Msg := Vstring.Append(Err_Msg, " was less than or equal to "); > > Err_Msg := Vstring.Append(Err_Msg, Natural'image(Max_I)); > > else > > raise I_Out_Of_Range; > > end if; > > exception > > when I_Out_Of_Range => > > Err_Msg := Vstring.To_Bounded_String("In procedure Test, I as input : "); > > Err_Msg := Vstring.Append(Err_Msg, Natural'image(I)); > > Err_Msg := Vstring.Append(Err_Msg, " was greater than "); > > Err_Msg := Vstring.Append(Err_Msg, Natural'image(Max_I)); > > Err_Msg := Vstring.Append(Err_Msg, " which raises the constraint 'I_Out_Of_Range'."); > > when others => > > Err_Msg := Vstring.To_Bounded_String("In procedure Test, something unexpected happened."); > > end Test; > > This procedure never propagates an exception. It returns normally in all cases. > As I said, you are not talking about exceptions in the calling code. You're > talking about returning error codes and checking them after the call. This has > all of the problems with returning error codes known from over 4 decades of > using C. These problems led to the inclusion of exceptions in more modern > languages; writing "C in Ada" is a step backwards. > > -- > Jeff Carter > "I'm particularly glad that these lovely children were > here today to hear that speech. Not only was it authentic > frontier gibberish, it expressed a courage little seen > in this day and age." > Blazing Saddles > 88 Here's a slight modification to the procedure you provided: with Ada.Text_IO; procedure exception_handling_1 is procedure test (OK : out Boolean) is -- empty declarative part begin -- test OK := True; raise Constraint_Error; -- exception -- when Constraint_Error => -- OK := False; end test; OK : Boolean := True; begin -- exception_handling_1 test (OK => OK); Ada.Text_IO.Put_Line (Item => "No exception"); Ada.Text_IO.Put_Line (Item => Boolean'Image (OK) ); exception when others => Ada.Text_IO.Put_Line (Item => Boolean'Image (OK) ); end exception_handling_1; When the exception handling section in the procedure test is commented out, the compiler returns the same pair of warning messages. When the program runs, the exception prevents the test procedure from completing. Then, the unhandled exception propagates up to the calling procedure and the "when others" exception in that procedure executes and does not modify the value of OK that was set in calling test. When the exception handling section in the procedure test is not commented out, the compiler has no warning messages. When the program runs, test now raises the "Constraint_Error" after the internal value of OK is set to TRUE. The now-included exception handler sets OK in the procedure to FALSE and completes. Upon completing the test procedure, control returns to the calling procedure. Since test handled the exception, the calling procedure does not receive the exception and terminates normally, printing the note "No exception", followed by the changed value of OK, which is now "FALSE". In other words, a called procedure that has its own exception handling can change the value of parameters in its interface and propagate the changes back to the calling procedure. I believe the proper lesson from this is that called procedures can handle exceptions and pass back diagnostic information about what led to the exception. The choice of where to handle the exception is up to the code designer. Sometimes it may be appropriate to handle the exception in the called procedure. If this is the selected strategy, then the called procedure can modify and return the "out" or "inout" variables. If the exception is handled in the called procedure, then it does not raise an exception in the calling procedure. If the called procedure does not handle the exception, the exception is propagated up to the calling procedure. Bruce B.