From: Alex Mentis on
On Mar 12, 4:13 am, Ludovic Brenta <ludo...(a)ludovic-brenta.org> wrote:
> Consider the procedure:
>
> type T is private; -- completion elided
>
> generic
>    with procedure Visit (Object : in out T);
> procedure Refresh (Object : in out T; Dirty : in out T) is
> begin
>    if Dirty then
>       Visit (Object);
>       Dirty := False;
>    end if;
> exception
>    when others =>
>       Dirty := True; -- warnings here
>       raise;
> end Refresh;
>
> GNAT says:
> warning: assignment to pass-by-copy formal may have no effect
> warning: "raise" statement may result in abnormal return (RM
> 6.4.1(17))
>
> The reason for the exception handler is to enforce a postcondition
> that Dirty must be True if Visit raises an exception. However the
> warnings suggest that the postcondition cannot be enforced this way.
> How should I rewrite my code?
>
> --
> Ludovic Brenta.

I think trying to "force" the parameter passing mode to a certain mode
is making this more complicated than necessary. One of the nice
things about Ada over other languages is that you generally shouldn't
have to worry about whether a parameter is copy-by-value or copy-by-
reference.

In this case, you are trying to use the exception handler to assign a
value to the local parameter Dirty so that it can get passed back to
the calling subprogram. This implies the calling subprogram has a
parameter in its scope that keeps track of dirtiness, too. Instead of
trying to set Dirty to True in Refresh, why not just raise a user-
defined exception (such as Dirty_Error) and have an exception handler
in the calling subprogram that catches this exception and sets the
*calling subprogram's* variable tracking dirtiness to True?

Alex
From: Ludovic Brenta on
Alex Mentis writes:
> On Mar 12, 4:13 am, Ludovic Brenta <ludo...(a)ludovic-brenta.org> wrote:
>> Consider the procedure:
>>
>> type T is private; -- completion elided
>>
>> generic
>>    with procedure Visit (Object : in out T);
>> procedure Refresh (Object : in out T; Dirty : in out T) is
>> begin
>>    if Dirty then
>>       Visit (Object);
>>       Dirty := False;
>>    end if;
>> exception
>>    when others =>
>>       Dirty := True; -- warnings here
>>       raise;
>> end Refresh;
>>
>> GNAT says:
>> warning: assignment to pass-by-copy formal may have no effect
>> warning: "raise" statement may result in abnormal return (RM
>> 6.4.1(17))
>>
>> The reason for the exception handler is to enforce a postcondition
>> that Dirty must be True if Visit raises an exception. However the
>> warnings suggest that the postcondition cannot be enforced this way.
>> How should I rewrite my code?
>>
>> --
>> Ludovic Brenta.
>
> I think trying to "force" the parameter passing mode to a certain mode
> is making this more complicated than necessary. One of the nice
> things about Ada over other languages is that you generally shouldn't
> have to worry about whether a parameter is copy-by-value or copy-by-
> reference.
>
> In this case, you are trying to use the exception handler to assign a
> value to the local parameter Dirty so that it can get passed back to
> the calling subprogram. This implies the calling subprogram has a
> parameter in its scope that keeps track of dirtiness, too. Instead of
> trying to set Dirty to True in Refresh, why not just raise a user-
> defined exception (such as Dirty_Error) and have an exception handler
> in the calling subprogram that catches this exception and sets the
> *calling subprogram's* variable tracking dirtiness to True?

That's an interesting suggestion but we've patched the run-time library
so that it dumps core on every exception; we use exceptions only for
exceptional situations and dumping core freezes the system for 30
seconds to produce a file roughly 300 MiB in size. So I would rather
not raise exceptions that are do not detect a bug.

--
Ludovic Brenta.
From: Alex Mentis on
On Mar 14, 10:21 am, Ludovic Brenta <ludo...(a)ludovic-brenta.org>
wrote:
> Alex Mentis writes:
> > On Mar 12, 4:13 am, Ludovic Brenta <ludo...(a)ludovic-brenta.org> wrote:
> >> Consider the procedure:
>
> >> type T is private; -- completion elided
>
> >> generic
> >>    with procedure Visit (Object : in out T);
> >> procedure Refresh (Object : in out T; Dirty : in out T) is
> >> begin
> >>    if Dirty then
> >>       Visit (Object);
> >>       Dirty := False;
> >>    end if;
> >> exception
> >>    when others =>
> >>       Dirty := True; -- warnings here
> >>       raise;
> >> end Refresh;
>
> >> GNAT says:
> >> warning: assignment to pass-by-copy formal may have no effect
> >> warning: "raise" statement may result in abnormal return (RM
> >> 6.4.1(17))
>
> >> The reason for the exception handler is to enforce a postcondition
> >> that Dirty must be True if Visit raises an exception. However the
> >> warnings suggest that the postcondition cannot be enforced this way.
> >> How should I rewrite my code?
>
> >> --
> >> Ludovic Brenta.
>
> > I think trying to "force" the parameter passing mode to a certain mode
> > is making this more complicated than necessary.  One of the nice
> > things about Ada over other languages is that you generally shouldn't
> > have to worry about whether a parameter is copy-by-value or copy-by-
> > reference.
>
> > In this case, you are trying to use the exception handler to assign a
> > value to the local parameter Dirty so that it can get passed back to
> > the calling subprogram.  This implies the calling subprogram has a
> > parameter in its scope that keeps track of dirtiness, too.  Instead of
> > trying to set Dirty to True in Refresh, why not just raise a user-
> > defined exception (such as Dirty_Error) and have an exception handler
> > in the calling subprogram that catches this exception and sets the
> > *calling subprogram's* variable tracking dirtiness to True?
>
> That's an interesting suggestion but we've patched the run-time library
> so that it dumps core on every exception; we use exceptions only for
> exceptional situations and dumping core freezes the system for 30
> seconds to produce a file roughly 300 MiB in size.  So I would rather
> not raise exceptions that are do not detect a bug.
>
> --
> Ludovic Brenta.

Well, I'm not sure I'm suggesting you raise extra exceptions, just
handle them in the calling subprogram instead of the called
subprogram. You're already re-raising the exception with the called
subprogram exception handler:

> >> exception
> >> when others =>
> >> Dirty := True; -- warnings here
> >> raise;

You don't have to create a user-defined exception. Consider the
following code:

type T is private; -- completion elided

generic
with procedure Visit (Object : in out T);
procedure Refresh (Object : in out T; Dirty : in out T) is
begin
if Dirty then
Visit (Object);
Dirty := False;
end if;

-- This handler isn't necessary, but I put it here to help illustrate
-- the changes I'm recommending.
exception
when others =>
raise;
end Refresh;

*****

procedure Calls_Refresh is

Obj : T;
Calling_Scope_Dirty : Boolean;

begin

-- potentially other code here

Dirty_Handler_Block :
begin

Refresh(Obj, Calling_Scope_Dirty);

exception
when others =>
Calling_Scope_Dirty : True;
-- potentially other handler code here

end Dirty_Handler_Block;

-- potentially other code here

end Calls_Refresh;
From: Robert A Duff on
Ludovic Brenta <ludovic(a)ludovic-brenta.org> writes:

> That's an interesting suggestion but we've patched the run-time library
> so that it dumps core on every exception;...

Then how can it ever get to the "when others" in Refresh?
Or do you mean it dumps core, and then the program continues
on past the point of the bug (propagates the exception,
handles it, etc)?

Is "dirty" a property of the object being visited?
If so, would it make sense to make it a component
of that object, and make sure that is passed by
reference (either by explicitly passing a pointer,
or by making the type limited or tagged)?

By the way, I think it makes perfect sense to have
different postconditions for normal return, and for
each exception that might be raised.

- Bob
From: Jeffrey R. Carter on
Ludovic Brenta wrote:
>
> That's an interesting suggestion but we've patched the run-time library
> so that it dumps core on every exception; we use exceptions only for
> exceptional situations and dumping core freezes the system for 30
> seconds to produce a file roughly 300 MiB in size. So I would rather
> not raise exceptions that are do not detect a bug.

Let me see if I understand this correctly: Visit raises an exception, which
freezes the system for 30 s and writes a large file. Then you handle the
exception, assign to Dirty, and re-raise the exception, again freezing the
system and writing the file.

Is that how this is expected to work?

--
Jeff Carter
"We'll make Rock Ridge think it's a chicken
that got caught in a tractor's nuts!"
Blazing Saddles
87