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

Jim Fulton (jfulton@dsjfqvarsa.er.usgs.GOV)
Mon, 6 Feb 1995 13:28:40 GMT

>>>>> "Guido" == Guido van Rossum <Guido.van.Rossum@cwi.nl> writes:
In article <9502052002.AA25336=guido@voorn.cwi.nl> Guido.van.Rossum@cwi.nl writes:

>> > This is indeed a problem, and this is why I proposed to let __enter__
>> > return an object whose __leave__ method is to be called. The object
>> > returned can then have a destructor (__del__ method) which aborts thr
>> > transaction if it has neither been committed nor aborted.
>>
>> Hm. I wonder if object destruction is deterministic enough to make
>> this work. Do you guarantee that an object created but not returned
>> from a function (due to an exception) will be destroyed before any
>> subsequent code runs? It is critical that if an exception occurs in
>> __enter__ (or after calling __enter__ but before calling suite) after
>> creating a transaction, that the transaction be aborted before any
>> subsequent computation takes place. Given comments I've read about
>> the non-determinism of garbage collection, I am reluctant to rely on
>> it for transaction management.

> The current *implementation* guarantees this; it uses reference
> counting and is completely deterministic (module bugs :-). There are
> some subtle things you need to know, e.g. if you make something a
> local variable it may survive longer because the stack frame is saved
> for the debugger, but there are ways to handle this.

OK, I guess I'd still like to avoid these subtleties if possible.
Always calling __leave__ seems a lot simpler to me.

>> Is there some problem with calling leave even if an exception is
>> raised in __enter__, or between completion of enter and execution of
>> suite? Something like:
>>
>> try:
>> object.__enter__()
>> ...execute suite...
>> except:
>> object.__leave__(exc_type, exc_value, exc_traceback)
>> else:
>> object.__leave__(None,None,None)

> Hmm... What do you do in this case if an interrupt occurs *before*
> any code in object.__enter__ has run? I could envisage a two-stage
> start, e.g.

I can handle this much easier than the other case, if __leave__ is
always called.

> object.__setup__()
> try:
> object.__enter__()
> except:
> object.__leave__(...)
> etc.

> But it is beginning to look cumbersome. Maybe we need a way instead
> to block asynchronous exceptions? (You could do this with the signal
> module but that's UNIX specific.) If there were a way to block
> asynchronous exceptions it could be part of the specs for the 'in'
> statement that async exceptions are not delivered while the __enter__
> is running, this would solve the problem. Of course if through a bug
> the __enter__ routine were to hang in an infinite loop it would be
> rather hard to kill...

I don't think a (additional) two-step startup is needed. For example,
for transaction processing (TP), I would use:

in Transaction():
...transaction code...

Here, the expression creates a new but not started transaction.
Transaction objects can have enough state for a __leave__ method to
tell whether the transaction has actually begun. If an exception
occurs after creating the transaction but before executing code in
__enter__, then the __leave__ method can tell that the transaction has
not started.

Note that in the above example, I am effectively using the Transaction
constructor to accomplish the same thing as your __setup__ routine.

Contrast the two approaches. First, if __leave__ is always called,
the TP designer has to consider the possibility that the transaction
may have been created, but not started. On the other hand, if the
__leave__ method is not called when an exception is raised in
__enter__ (or between __enter__ and the execution of suite), then the
TP designer has to use knowledge of the subtleties of the garbage
collector (GC) to correctly design the TP mechanism. This is
knowledge that I currently don't possess. I don't like the idea of
coupling the semantics of the new mechanism with the semantics of the
current GC.

At the Python workshop, there was some discussion of alternate GC
strategies. Do you really want to commit to current GC semantics now?
I spent some time on the ANSI Smalltalk committee and the vendors on
that committee were extremely unwilling to commit to particular GC
semantics. In fact, they did not (at the time) want to even guarantee
that an ANSI Smalltalk system would actually do garbage collection at
all. On the other hand, Smalltalk does not use destructors, so the
execution of finallization code is not an issue. Still, might not
future implementations of Python want to use less deterministic GCs?
Would committing to the current GC timing semantics prevent
implementation of reference following garbage collectors in the
future?

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