[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

tracing methods

    Date: 19 Mar 85 08:23:09 EDT (Tue)
    From: Larry Hunter <hunter at YALE.ARPA>

    Is there an easy way of tracing methods?  It seems like they are just 
    plain procedures (hence tracable) but I don't know how to pass their    
    location to trace....

All TRACE does is to SET the location you specify to a new procedure
which simply prints trace information, calls the old procedure, prints
more trace info, and returns the value.  In other words, TRACE doesn't
require any hidden or implementation-dependent features of T; you could
write it as



	    (FORMAT T "Calling ~S with arguments ~S~%" PROC ARGS)
	      (FORMAT T "Returned from ~S with value ~S~%" PROC VAL)


There are at least two other kinds of TRACE-like facilities that one
would want:

  (a) a destructive version, which destructively alters a procedure
      so that the procedure would print trace information.

  (b) a destructive version which operates on ALL closures over
      a given LAMBDA-expression.

Neither of these is semantically well-defined ("sameness" of
LAMBDA-expressions and closures is not well defined - closures and/or
lambda-expression may be copied or shared by the implementation in any
way it sees fit), and neither could be written in T (these two facts are
related).  For example:

  (P (LAMBDA () A)
     (LAMBDA () A)))

A compiler might implement the two arguments to P as identical (EQ)
pointers, while an interpreter might implement the two arguments as
different (non-EQ) closures over different (non-EQ) LAMBDA-expressions.
A different compiler could conceivably implement the two arguments as
different closures over the same LAMBDA-expression.  Closures and
LAMBDA-expressions are much like numbers in this sense (again, an
intentional feature) - asking to trace a closure FOO would be like
asking to notified every time the number 37764999682 is ever multipled
by anything.  When is one number the same as some other number?  Sure,
if the implementation represnts that integer as a "bignum," the storage
for the number could be clobbered so that the generic arithmetic package
sees that that number wants to be "traced," and the right thing happens.
But that number may have been computed in two different ways, and one of
the two objects representing that number might be "traced" when another
isn't.  This would be very confusing.

It's not even clear how one would specify the type (b) tracing, since
there is no way to name a LAMBDA-expression.  (One might like to point
at the source code with a mouse - anyone care to implement such a

Of course, any of this might be done by a particular interpreter in a
certain way; maybe that's the right thing to do - hack EVAL.  But this
of course means that the tracing operations won't work with closures
created by other compilers' code.

There are many other interesting ways to trace things: e.g., trace all
closures over a LAMBDA-expression X sitting inside LAMBDA-expression Y
whose environments contain a given Y-closure's environment as a subset.
E.g., trace the FOO method for some object C, or trace the FOO methods
of all objects C returned as the value of some lambda-expression in the
code for a given *closure* D, etc.... these are distinct and useful

Method tracing in particular might be useful enough to warrant a change
in the operation system itself.  This relates to the old problem of
altering or adding methods, though, which is also something I don't

Your question touches on some deep problems, so, as usual in T when a
user wanders off into semantic backwaters, you lose.  If T weren't
lambda-calculus then most of these problems wouldn't arise (because
there would be no closure/lambda-exp distinction), so perhaps
lambda-calculus and its nice invariants are themselves suspect.

I hope you're now as confused as I am about all this.