!standard B.01(46) 04-02-27 AC95-00094/01 !class confirmation 04-02-27 !status received no action 04-02-27 !status received 04-02-26 !subject !summary !appendix From: Peter Hermann Sent: Thursday, February 26, 2004 2:42 AM In the following strongly reduced code sequence I demonstrate an unexpected and not welcomed nasty effect of an exception raised in the wrong place. It may possibly be an effect of "call by name"/"call by reference". Do I have to suffer an Ada language disadvantage or is this a Gnat compiler weakness? In any case, I would be greatful for a workaraound. ------------------------------------------------------------------------ with ada.text_io; use ada.text_io; procedure trap is buffer : string(1..256); last:integer; matrikel7h : string(1..7); matrikelast : natural range 7..7; procedure dialog(prompt : string; result : out string; resulast : out natural) is begin loop put_line (prompt); get_line(buffer,last); -- last other than 7 e.g. < 7 zwang: begin result:=string'(result'range=>' '); result(1..last):=buffer(1..last); --raises fine for last>7 resulast:=last; -- expected raise of exception (wanted) exit; exception when others => put_line("***rejected " & buffer(1..last)); end zwang; end loop; end dialog; begin -- trap main program dialog("7-stellige Matrikelnummer",matrikel7h,matrikelast); exception when others => put_line("raised exception after return :-("); end trap; **************************************************************** From: Randy Brukardt Sent: Thursday, February 26, 2004 5:06 PM The exception is raised exactly where it is supposed to be raised. The out parameter has subtype Natural, and certainly a value in 0 .. 6 is a legal value of Natural. Elementary types are by-copy types, and the subtype check for 7..7 occurs when the result is copied back to the actual parameter. There's no logic problem with the language semantics. If you think about it, it couldn't be any other way. First, a prime principle of Ada is the contract, and the contract for the out parameter is subtype Natural. That means that you can use the parameter as a value of Natural within the subprogram without worrying about the subtype of the actual. (Yes, by-reference types with defaulted discriminants differ in this - a nod to pragmatics, I think, and one that causes no end of implementation and usage trouble.) Second, the implementation of the check that you're expecting would be relatively expensive, as it would require passing in the subtype bounds with every in out and out parameter. That would triple the parameter passing overhead and make Ada incompatible with every other language out there (and in particular make even well-written C code unable to match Ada semantics). It would be a sure-fire way to make Ada live up to its (unfair) reputation for being slow. In any case, I'm not sure why you posted this here; this isn't a place to post bug reports about compilers! > In any case, I would be greatful for a workaraound. Without knowing what it is that you are trying to do, it's impossible to suggest much. I do think it is dubious to depend on the raising of Constraint_Error as part of the normal functioning of your application. That's especially true for range checks, which are trivially written in the rare case where they are needed. They are best reserved for finding program bugs - in which case, where the exception is raised does not matter. Thus, the obvious workaround to explicitly do what you were expecting Ada to do for you: pass the bound(s) into the subprogram and check them yourself. **************************************************************** From: Peter Hermann Sent: Friday, February 27, 2004 4:14 AM Randy, I have not much of an objection against your reasoning. Indeed I thank you for your valuable elaboration. From the point of view of the subprogram it MAY BE in fact on the pragmatic side to postpone the raising of the exception towards the return jump, especially when 1. the formal parameter further changes its value 2. the subprogram is at library level. In any case I am feeling not comfortable as an ordinary user of the Ada language to be dependent on parameter mechanisms. On Thu, Feb 26, 2004 at 05:05:45PM -0600, Randy Brukardt wrote: > In any case, I'm not sure why you posted this here; this isn't a place to > post bug reports about compilers! As you have proven by your reply it is a question of basic principles. > > In any case, I would be greatful for a workaraound. I found a workaraound myself (see far below). Justification: > Thus, the obvious workaround to explicitly do what you were expecting Ada to > do for you: pass the bound(s) into the subprogram and check them yourself. This is of course a working solution albeit ancient way of Fortran. I am usually against misuse of exception handling in normal logics. However in exceptionally wrong user data I prefer this elegant handling method in order to have smaller and more readable code. Peter Hermann ps.: The following work_around is unfortunately not possible when the subprogram is on library level )-: [--*** indicate differences to subprogram trap] ------------------------------------------------------------------------ with ada.text_io; use ada.text_io; procedure trap2 is buffer : string(1..256); last:integer; matrikel7h : string(1..7); subtype seven is integer range 7..7; --*** matrikelast : seven; --replacing: natural range 7..7; --*** procedure dialog(prompt : string; result : out string; resulast : out seven) --*** is begin loop put_line (prompt); get_line(buffer,last); -- last other than 7 zwang: begin result:=string'(result'range=>' '); result(1..last):=buffer(1..last); resulast:=last; -- expected raise of exception (wanted) exit; exception when others => put_line("errmsg: rejected " & buffer(1..last)); end zwang; end loop; end dialog; begin -- trap2 main program dialog("7-stellige Matrikelnummer",matrikel7h,matrikelast); exception when others => put_line("raised exception after return :-("); end trap2; **************************************************************** From: Peter Hermann Sent: Friday, February 27, 2004 4:34 AM No, it's not a work-around... :-( I beg your pardon ****************************************************************