bug-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: %destructor feedback


From: Joel E. Denny
Subject: Re: %destructor feedback
Date: Mon, 17 Oct 2005 13:21:41 -0400 (EDT)

On Mon, 17 Oct 2005, Wolfgang Spraul wrote:

the reason I prefer the automatic cleanup is that I generally like 'atomic'
behavior of functions (actions in this case). Atomic = either the
function/action _completely_ succeeds, or _completely_ fails. If it fails,
the resulting state should be as if the function was never called.
If you move the responsibility of cleanup when doing YYERROR/YYABORT into the
action, you break this atomic design: If the action fails, it must now return
in a different state than when it was called, otherwise the right-hand
semantic values will be leaked (never cleaned up by anyone).

Correct me if I'm wrong: in your above argument (not the one below), you're arguing for a clean interface for the user semantic actions for *the sake of the semantic actions' caller*. That is, the caller would be guaranteed this atomic-like behavior: the function/action always has either the full intended effect or no effect at all. Is this right?

Assuming I'm following you, I appreciate your design. For some code, it seems to me your design would make a lot of sense. However, I have a few counter-arguments for bison:

1. Again, it appears your above argument is mainly about simplifying the interface *for the sake of the caller*. The caller is bison-generated code. In other words, your above (not below) argument does not seem to offer advantages for the bison user.

At the moment, it seems that it would actually be easier to rewrite bison to consistently follow my approach since it already follows it in most cases: YYERROR in GLR or LALR(1), YYABORT in GLR. I'm not familiar enough with the C++ skeleton to comment on it. Akim?

2. Again, I believe my design is simpler for the user to remember: in all cases, you must clean up RHS semantic values in any semantic action you provide. That is, YYABORT and YYERROR are not exceptions to the rule. I discuss whether this is simpler for the user to *implement* below.

3. In general (not just bison) for the sake of memory management, I often find my design easier for both the caller and the called function/action: if the called function/action *ever* takes responsibility for memory that the caller passes it, it *always* takes responsibility for the memory regardless of success/failure.

For the called function/action's code, this often means that, once I hit an error condition, I don't have to somehow undo what I may have already done within the function/action: freeing some of that memory or passing responsibility for it to some other function. Instead, I just have to guarantee that I fully free the rest of that memory before returning the error condition.

For the caller's code, this often means I simply have less work to do. I don't have to think about freeing after the function/action returns regardless of the status. I find this to be better encapsulation.

Note my use of the word `often'. Sometimes your design would actually be easier. I think it depends on the kind of code you're writing. For situations in which my design would be preferable, your design may prove very frustrating in the called function/action. How do I undo passing memory management to another function? Will I have to rewrite my logic in some confusing manner? For situations in which your design would be preferable, the worst that can happen with my design (for bison anyway) is some additional memory clean-up code. Or so it seems to me. What do you think?

On top of this design issue there is a practical advantage: There must be a
built-in cleanup anyway, so the manual cleanup of RHS values is redundant,
only increases code size for no good reason.

I think this depends on the semantic action. For example, I have semantic actions that don't call YYABORT until after already storing the RHS semantic values in a structure that's responsible for their deletion. Thus, in such semantic actions, there's less code if I don't have to somehow undo this shift in memory responsibility before invoking YYABORT.

I wonder if my design plus the following feature would help alleviate your redundancy concern:

On Monday 17 October 2005 08:34, Joel E. Denny wrote:

I've also noticed that the bison documentation says:

   Note that in the future, Bison might also consider that right hand
   side members that are not mentioned in the action can be destroyed.

If this is implemented, I believe that it should be implemented
consistently for all three cases: the user's semantic action completes
successfully, it calls YYABORT, or it calls YYERROR.

In other words, if you have an action that does nothing but invoke YYABORT/YYERROR, clean-up would be automatic.

Joel




reply via email to

[Prev in Thread] Current Thread [Next in Thread]