One good reason for introspection (was: "What is the name of what called me?")

Russell Turpin rturpin at do.not.use
Sun Oct 24 10:18:57 EDT 1999


Debuggers are good, but I hate to assume that software (even
mine) is 100% bug-free once it is in a production environment.
It can be very difficult to reproduce the conditions that 
create an infrequent bug unless the program itself leaves 
behind some information, a trace, for post-execution analysis.

In C and C++, I have always used macros to generate trace
files.  Tracing is always optional, and the advantage of a 
macro is that the test can be outside the expensive function
call.  With Python (a) there is no macro capability, and 
(b) I suspect the function call isn't that expensive in the
larger scheme of things.  This makes it tempting to wrap trace
functions together with the required data as a trace object
that is inherited by any object that wants to perform tracing.

Consider, now, that I decide some application methods should
have their entry and exit traced, possibly along with entry
parameters and exit values.  The application method must be
responsible for formatting the part of the message displaying
values, since it alone deals with these.  But where should
the code be that says it was foo() that has been entered or
exited?  One answer is: let foo() do it.  The problem with
this is that it reproduces foo's name in places other than
the def statement.  Like comments, these are often left
behind when future enhancement copies and revises foo() to 
create spam() and eggs().  (If foo() were merely renamed to 
bar(), that would not be so bad, since anyone reading the 
trace would think "there is no foo(), so I must search for 
the trace procedure that thinks it is told it is in foo()."  
But to have two or three functions generating the same trace 
statements is a real recipe for confusion!)

The better technique is to have the trace procedure snag the 
name of its caller.  Hence, my question that gave rise to 
this debate.

On the larger issue, I am somewhat ambivalent.  I see no reason
of proper behavior for a program to have access to the names of 
any of its objects.  Philosophically, names live in design space, 
not execution space.  Names are required ONLY for debugging, 
tracing, and other forms of program analysis.

BUT.  I have never met a programming environment that provides
so rich an environment for programming analysis that software
developers would want for nothing else in this regard.  Given
this, I think it behooves language designers to provide 
introspection features, including ways to peek at the call
stack without generating an exception.  Furthermore, if it is
alright to peek at the call stack for exception handling, I 
see no reason to forbid it when executing non-exception code.

Russell




More information about the Python-list mailing list