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

Jim Fulton (jfulton@disqvarsa.er.usgs.GOV)
Wed, 1 Feb 1995 18:09:47 GMT

>>>>> "Ty" == Ty Sarna <tsarna@endicor.com> writes:
In article <D355o7.I83@endicor.com> tsarna@endicor.com (Ty Sarna)
writes:

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

Right.

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

In my transaction model, there are THREE ways to exit:

1. Normal completion (need to commit)
2. Python exception (need to abort)
3. Transaction aborted by transaction processing system, independent
of transaction code execution (already aborted).

Other applications may have different requirements. I'd like to see
an approach that works for many different applications.

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

This approach is different from what I proposed. In my proposal, a
callable object (e.g. a function) is given the code to execute. Your
approach uses two functions (methods of transaction objects) that
setup for and then wrap up after a transaction has been executed. You
have no control over when or if the code is executed. In your
proposal, what happens if an exception is raised in the __enter__
function?

In your model, you have no control about when or if the code is
executed. With my approach, the callable object that controls
execution may delay execution, or even choose not to execute the code
at all. My approach allows applications like:

exec thread:
...some code that is executed in a separate thread...

or

exec widget.addCallback('some callback name'):
...some code to handle callbacks...

I can certainly live with your approach, but I think mine is more
general.

> 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()
> #...

For my transaction model, I need more information. I need to know
what type of exception was raised, and other applications might want
the exception value. I suppose I could get these from sys.exc_type,
and sys.exc_value. (?)

> 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

Yup.

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

See my response to Guido's note.

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

I agree. Please forget I ever mentioned it.

> "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 certainly be useful for transactions, but I'm not sure how
it would relate to other applications.

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

I agree.

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