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

Ty Sarna (tsarna@endicor.com)
Sun, 29 Jan 1995 00:36:06 GMT

In article <9501281121.AA16443=guido@guppie.cwi.nl>,
<Guido.van.Rossum@cwi.nl> wrote:
> 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.
[...]
> 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!

It doesn't have the same power, for one important reason: it's not
possible to tell in the finally: case how the first suite was exited.
This is absolutely crucial for transactions!

When you talk about locking like the above or Jim and I talk about
transactions, we're talking about entering and leaving a state (in the
sense of a state diagram). We both have code that needs to be run on
entering the state, and code that needs to be run on leaving the state.
In the case of locking, you need to lock on entering, and unlock on
leaving. try...finally... or locking:... would work fine for this.

However, the transaction state is different. We need to "begin" on
entering, but then there are TWO ways to exit the state: commit and
rollback. We need to commit on success and rollback on failure (eg on
an exception). try...finally... and locking... don't provide any way for
the "leave" code to know which is the case. So, we need something that
can support that.

> 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'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.

How about "enter"?

enter_stmt: 'enter' expr ':' suite

This is basicly your "locking" statement, with __lock__/__unlock__
renamed to __enter__/__leave_ (for generality) and the addition
of an "excepts" argument to the __leave__.

It would call object.__enter__() before entering the suite, and
guarantee object.__leave__(excepts) is called after leaving it.
__leave__ is called with excepts=1 if an exception was raised and not
handled inside the suite. If the suite is exited normally, __leave__ is
called with excepts=0.

e.g, for transactions, I'd have a single transaction manager object
with methods like this:

class Transaction:
#...
def __enter__(self):
begin_transaction()
def __leave__(self, excepts):
if excepts:
rollback_transaction()
else:
commit_transaction()
#...

then I'd use it this way:

# once at start of program, since only one transaction manager is needed.
from wherever import Transaction
transaction = Tranaction()

#...

try:
enter transaction:
account1.withdraw(100)
account2.deposit(100)
except OverDraught:
print "Insufficient funds!"
except WireError:
print "Communications error with bank. Try again later."

Or imagine your locking example:

# obj defines __enter__ as lock and __leave__ as unlock. __leave__
# doesn't care in this case wether the excepts arg is 1 or 0.

enter object:
# it's locked now, do stuff with it

> 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?

I don't think that the suites need to be passed to the object. As far
as the else clause, you are right that it's not strictly neccesarry.
"enter" could have the except...else... syntax built in for
convenience. That would simplify the above example to:

enter transaction:
account1.withdraw(100)
account2.deposit(100)
except OverDraught:
print "Insufficient funds!"
except WireError:
print "Communications error. Try again later."

This would be a little more convenient, especially since anyone who
is using "enter" is obviously planning for exceptions to happen and
might want to handle them right there instead of wrapping an additional
try...except.. around the enter. That's just syntactic sugar, though.
I'm not sure if it's really worth it.

How does this sound?

-- 
Ty Sarna                 "Don't be wet or humidity, for the cause of
tsarna@endicor.com        electric obstacle." -- Warning from a manual