Re: Jim Fulton : Extensible compound statements -- new exec flavor

Jim Fulton (jfulton@disqvarsa.er.usgs.GOV)
Wed, 1 Feb 1995 14:20:19 GMT

>>>>> "Guido" == Guido van Rossum <Guido.van.Rossum@cwi.nl> writes:
In article <9501281121.AA16443=guido@guppie.cwi.nl> Guido.van.Rossum@cwi.nl writes:

> Jim Fulton asked my opinion about his proposal for a "transaction"
> statement. I'd like to see this discussion back in public (I sort
> of missed the first round) so I'm cc'ing my reply to the list, but I'm
> not quoting Jim's material -- you can look it up in the mailing list
> archives if you need to <URL:http://www.cwi.nl/~guido/hypermail/>.
> (If Jim thinks parts are unclear he can post his own message to the
> list or add it to his reply to this one.)

See another posting parallel to this one that gives the text of a more
carefully described proposal.

> My first impression: yes, I've always been thinging about a syntactic
> form that makes it possible to cleanly define things like
> transactions, critical sections etc. We have try-finally (which is
> *different* from try-except -- the two cannot be merged in one try
> statment), but it has a race condition unless used very carefully.

> If you put the begin-transaction operation inside the try suite, like
> this:

> try:
> T.begin()
> ...code...
> finally:
> T.end()

> there's a possibility that if it fails the end-transaction will find
> the transaction not yet begun; if you put it outside the try clause,
> like this:

> T.begin()
> try:
> ...code...
> finally:
> T.end()

> then a KeyboardInterrupt or other asynchronous signal may arrive
> before the try-finally is set up. It is also somewhat verbose to use.
> I had been thinking along the lines of:

> locking object:
> suite

> which would be equivalent, except for the fixed race condition, to:

> object.__lock__()
> try:
> suite
> finally:
> object.__unlock__()

> I'm not sure whether this has the same power of your proposal, since
> you're a little weak on explaining the semantics.

Hm, I thought the semantics were clear. Here is another stab at my
original proposal, with a small addition for return statements.
Given:

exec expr:
suite

Call the result of expr with the code object compiled for suite, and
the global and local dictionaries. Given:

exec expr:
suite
else:
else_suite

Call the result of expr with the code object compiled for suite,
the global and local dictionaries, and the code object compiled for
else_suite. In the execution of either suite, continue. break, and return
statements raise exceptions, ContinueException, BreakException, and
ReturnException. In the case of a ReturnException, the value of the
exception is the returned value.

The proposal intentionally says nothing about what the result of expr
will do when called. For example, it does not specify how, when, or
if the code objects associated with the suites will be executed. Now
does it specify how exceptions will be handled.

If this is still unclear, then perhaps some specific questions could
be raised as I'm not sure what else to clarify.

> I don't like hijacking the exec keyword for this. The exec statement
> is intended to execute dynamically constructed code and you'r using it
> for Something Completely Different (TM).

I was trying to avoid using a new keyword. I'm not suggesting a
TM-specific addition. The exec statement allows greater control over
execution. I'm suggesting a way for the programmer to provide their
own application- or domain-specific execution control semantics. I
don't see this as different, but if you want to use a different
keyword, that's fine with me.

> I'm not so happy with
> "lock" as a keyword either, but I think that if we want an addition
> like this to the language it warrants inventing good, clean syntax for
> it. As you point out it has much potential.

Absolutely.

> I'm not sure of the purpose of the "else" clause in your proposal, but
> this may be because I also don't understand why you want the code for
> the suites packed up and passed to your transaction object. What's
> the purpose of this?

There are two questions here:

1. Why "else"
2. Why pass the code to the result callable object.

I'll try to answer the second question first.

I want to pass the code object because I want allot of control over
how, when and if the code is executed.

In the case of transaction processing, I need to begin the transaction
prior to executing the code and I need to execute other code depending
on whether any exceptions are raised and on which exceptions were
raised. Depending on the nature of the exception, after the execution
of the code, I may need to commit the transaction, abort the
transaction, or do neither (because the transaction may already have
been aborted).

Note that In my application, the callable object computed in the exec
statement is not a transaction object, but rather a callable object,
such as a function, that controls the creation and termination of
transaction objects:

def Code(suite,global,local,else=None):

Transaction.Begin()
try:
exec suite in global in local
Transaction.End()
except Transaction.AbortException:
raise sys.exc_type,sys.exc_value
except:
Transaction.Abort()
raise sys.exc_type,sys.exc_value

Note that in the case of a Transaction.AbortException, I neither abort
or commit the transaction, because the transaction has already been
aborted.

Again, I want control over the context in which the code is executed
*and* I want to encapsulate this control so that user code need not
depend on the specific control strategy.

The purpose of the "else" keyword in my original proposal was to provide
some kind of hook for domain- or application-specific branching. This
part of the proposal is weak and none of the applications that I have
thought of need it. I hereby endorse removing the "else" suite from
the proposal.

> Finally I'm not sure if you grasp the power of try-finally, since your
> examples are all phrased in terms of try-except, sometimes with a
> unqualified except that re-raises the original exception after some
> clean-up. This is what try-finally is for!

I think I do grasp try-finally. The problems I have with it, aside
from the race condition, are:

- for the aplications I envision, the code in the finally clause
depends on whether and which exceptions are raised, and
- I want a mechansism to hide the details of the transaction
management strategy from the application programmer. I want the
application programmer to be able to use code like:

exec transaction:
...some code...

try:
exec transaction:
...some code...
except ...some exception...:
...some *application-specific* exception handling code that
does not have to worry abouut commit/abort issues...


--
-- Jim Fulton      jfulton@mailqvarsa.er.usgs.gov    (703) 648-5622
                   U.S. Geological Survey, Reston VA  22092 
This message is being posted to obtain or provide technical information
relating to my duties at the U.S. Geological Survey.