From: bradb
Subject: Interactive debugging tips...
Date: 
Message-ID: <1127750252.939911.260100@g14g2000cwa.googlegroups.com>
I hear lots about how one can interactively debug a Lisp program as it
is running.  I take this to mean that I can manipulate data structures
and modify functions as my program is running its main loop.  Or are
people just meaning the REPL when they say interactive?
If it is possible to tinker with a running image, how does one go about
doing it?  Or is this not a topic for a beginner :)

Thanks
Brad

From: Christopher C. Stacy
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <uirwnrcvt.fsf@news.dtpq.com>
"bradb" <··············@gmail.com> writes:

> I hear lots about how one can interactively debug a Lisp program as it
> is running.  I take this to mean that I can manipulate data structures
> and modify functions as my program is running its main loop.  Or are
> people just meaning the REPL when they say interactive?
> If it is possible to tinker with a running image, how does one go about
> doing it?  Or is this not a topic for a beginner :)

I'm not quite sure what you heard, but all computer programming
languages allow you to manipulate data structures as the program 
is running.  Lisp allows you to do things like programatically 
introduce new functions, or alter the data-type of an existing
data structure, while it is running.

What is it that you are trying to do?
From: bradb
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <1127755817.012152.201310@o13g2000cwo.googlegroups.com>
:)
What I mean is - can I change the code/data of a running Lisp program,
without stopping the program?

ie, my program is
(defvar *stop* nil)
(while (= stop nil)
 .... do body )

Then from another "thread" that has a REPL can I go (setf stop t) and
have the loop terminate?

Brad
From: Marco Baringer
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <m2zmpzpw0c.fsf@soma.local>
"bradb" <··············@gmail.com> writes:

> :)
> What I mean is - can I change the code/data of a running Lisp program,
> without stopping the program?
>
> ie, my program is
> (defvar *stop* nil)
> (while (= stop nil)
>  .... do body )
>
> Then from another "thread" that has a REPL can I go (setf stop t) and
> have the loop terminate?

yes, but you can do that in any language (your example amounts to a
simple form of ipc via shared state).

-- 
-Marco
Ring the bells that still can ring.
Forget the perfect offering.
There is a crack in everything.
That's how the light gets in.
	-Leonard Cohen
From: bradb
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <1127757422.748037.89200@g47g2000cwa.googlegroups.com>
That is true I guess.  I should perhaps ask "is this feature already
built in?"  At the moment I am using Vim + Vilisp.  If Slime has this
IPC feature then it might be a compelling reason to invest in it.  I
really ought to invest in learning it anyhow - but at the moment a new
editor + a new language might be a bit much.
BTW - I watched your Slime demo video last night - impressive stuff

Brad
From: Thomas F. Burdick
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <xcvzmpzhcmi.fsf@conquest.OCF.Berkeley.EDU>
"bradb" <··············@gmail.com> writes:

> That is true I guess.  I should perhaps ask "is this feature already
> built in?"  At the moment I am using Vim + Vilisp.  If Slime has this
> IPC feature then it might be a compelling reason to invest in it.  I
> really ought to invest in learning it anyhow - but at the moment a new
> editor + a new language might be a bit much.
> BTW - I watched your Slime demo video last night - impressive stuff

What you're thinking of is probably not what you want to do.  You
certainly *can* do that from another thread, and slime's thread
browser is useful here.  However, you probably want to use C-c C-c to
interrupt the Lisp, redefine a function, then continue; or then
restart a stack frame.  Of course, you can also interrupt any thread
this way (Slime's thread browser is really useful here).

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Alan Crowe
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <864q87mxsr.fsf@cawtech.freeserve.co.uk>
brad.beveridge asks
> What I mean is - can I change the code/data of a running Lisp program,
> without stopping the program?

Something that I've done (to delay having to learn about
threads) is to use LISTEN, which is ANSI CL, from the
streams dictionary.

For a simple example consider this little loop that slowly
prints out the values of a function.

* (defvar *i* 0)

*I*
* (defun foo () (print (expt *i* 4)))

FOO
* (loop (incf *i*)(foo)(sleep 2))

1 
16 
81 
256 

Interrupted at #x280CB958.

How can we keep talking to the REPL while this is going on?
We can do this in a single thread by listening periodically
to see if there is input which we pass to our own embedded
REPL.

(loop (incf *i*)(foo)(sleep 2)
	(when (listen)
	  (print (eval (read)))))

Then we can do things such as reset the count

20736 
28561 
(setf *i* 0)
38416 
0 
1 
16 

or change the function

50625 
65536 
83521 
104976 
(defun foo () (format t "~R~%" *i*))
130321 
FOO twenty
twenty-one
twenty-two
twenty-three

Under CMUCL this rapidly becomes frustrating because when
you make an error the only restart is to return to the
top-level. This breaks you out of your loop.

I wrote an interaction macro to wrap the body code and the
REPL in appropriate restarts.

;;;; repeat-interactively
;;;
;;; Allows the programmer to work on running code
;;; 
(defmacro repeat-interactively ((&optional (tick 1)
					   (count-var 'count)
					   (prompt "~&>>-~A-> "))
				&body code)
  `(flet ((prompt-user()
	    (declare (special prompt ,count-var ))
	    (format t prompt ,count-var)
	    (force-output)))
      (let ((,count-var 0)
	    (prompt ,prompt)
	    (tick ,tick))
	(declare (special ,count-var prompt tick))
	(prompt-user)
	(catch 'stop
	  (loop
	   (restart-case
	    (progn ,@code (incf ,count-var)(sleep tick))
	    (fixed () :report "Resume processing."))
	   (when (listen)
	     (tagbody top
		      (restart-case
		       (progn
			 (print (eval (read)))
			 (prompt-user))
		       (shrug () :report "Continue processing."
			      (prompt-user))
		       (retry () :report "Evaluate another form."
			      (prompt-user)
			      (go top)))))
	   )))))

I don't use it much. It is usually adequate to interrupt the
running code with ctrl-C ctrl-C, make the change, and then
use the continue restart.

There is one cool trick which I suggest you try. Make the
loop write to a file. Use finish-output to flush the buffers
and the Unix command tail -f to what the output.

Make it tabulate something that is compute intensive, so
that interpreted code is taking a second or two for each
entry. Then compile the code and watch it suddenly get faster.
Coming from a C background, I find this completely
mind-boggling.

I don't think that there is anything difficult about using a
REPL in a separater thread to change function
definitions. However, if you try writing code that uses
multiple threads in a serious way, you have to use locks to
stop the different threads from stepping on each others
toes, and it is this that I have shied away from.

Alan Crowe
Edinburgh
Scotland
From: Kenny Tilton
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <KV_Ze.1126$Fc4.259@twister.nyc.rr.com>
bradb wrote:
> :)
> What I mean is - can I change the code/data of a running Lisp program,
> without stopping the program?
> 
> ie, my program is
> (defvar *stop* nil)
> (while (= stop nil)
>  .... do body )
> 
> Then from another "thread" that has a REPL can I go (setf stop t) and
> have the loop terminate?

Shucks, I did exactly that once with debug output streaming to my 
listener window. I just typed more or less blindly and hit return. I was 
careful not to leave off the asterisks on *stop*, so it worked.

:)

-- 
Kenny

Why Lisp? http://wiki.alu.org/RtL_Highlight_Film

"I've wrestled with reality for 35 years, Doctor, and I'm happy to state 
I finally won out over it."
     Elwood P. Dowd, "Harvey", 1950
From: Marco Baringer
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <m24q87ssht.fsf@soma.local>
"bradb" <··············@gmail.com> writes:

> I hear lots about how one can interactively debug a Lisp program as it
> is running.  I take this to mean that I can manipulate data structures
> and modify functions as my program is running its main loop.  Or are
> people just meaning the REPL when they say interactive?
> If it is possible to tinker with a running image, how does one go about
> doing it?  Or is this not a topic for a beginner :)

they mean 'just the REPL,' but you don't realize what that means :)

there's been a lot of discussion in this group on this exact topic,
use goole. you could also look at some of the entries in bill
clementson's blog or this c.l.l thread:

http://groups.google.com/group/comp.lang.lisp/browse_frm/thread/dd7a9e6b1985ee09/c7eda44807809c9d

-- 
-Marco
Ring the bells that still can ring.
Forget the perfect offering.
There is a crack in everything.
That's how the light gets in.
	-Leonard Cohen
From: Pascal Costanza
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <3pqmg3Fbm0asU1@individual.net>
bradb wrote:
> I hear lots about how one can interactively debug a Lisp program as it
> is running.  I take this to mean that I can manipulate data structures
> and modify functions as my program is running its main loop.  Or are
> people just meaning the REPL when they say interactive?
> If it is possible to tinker with a running image, how does one go about
> doing it?  Or is this not a topic for a beginner :)

Here is an example session:

CL-USER 1 > (defun f (x)
               (g (+ x 1)))
F

CL-USER 2 > (f 42)

Error: Undefined operator G in form (G (+ X 1)).
   1 (continue) Try invoking G again.
   2 Return some values from the form (G (+ X 1)).
   3 Try invoking something other than G with the same arguments.
   4 Set the symbol-function of G to another function.
   5 Set the macro-function of G to another function.
   6 (abort) Return to level 0.
   7 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed,  or :? for other 
options

CL-USER 3 : 1 > (defun g (x)
                   (* x x))
G

CL-USER 4 : 1 > :c 1
1849

CL-USER 5 > (defclass person ()
               ((name :initarg :name
                      :accessor person-name)))
#<STANDARD-CLASS PERSON 10076A1F>

CL-USER 6 > (defparameter *pascal*
               (make-instance 'person :name "Pascal"))
*PASCAL*

CL-USER 7 > (person-name *pascal*)
"Pascal"

CL-USER 8 > (person-address *pascal*)

Error: Undefined operator PERSON-ADDRESS in form (PERSON-ADDRESS *PASCAL*).
   1 (continue) Try invoking PERSON-ADDRESS again.
   2 Return some values from the form (PERSON-ADDRESS *PASCAL*).
   3 Try invoking something other than PERSON-ADDRESS with the same 
arguments.
   4 Set the symbol-function of PERSON-ADDRESS to another function.
   5 Set the macro-function of PERSON-ADDRESS to another function.
   6 (abort) Return to level 0.
   7 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed,  or :? for other 
options

CL-USER 9 : 1 > (defclass person ()
                   ((name :initarg :name
                          :accessor person-name)
                    (address :initarg :address
                             :accessor person-address)))
#<STANDARD-CLASS PERSON 10C786F7>

CL-USER 10 : 1 > :c 1

Error: The slot ADDRESS is unbound in the object #<PERSON 10C77513> (an 
instance of class #<STANDARD-CLASS PERSON 10C786F7>).
   1 (continue) Try reading slot ADDRESS again.
   2 Specify a value to use this time for slot ADDRESS.
   3 Specify a value to set slot ADDRESS to.
   4 (abort) Return to level 0.
   5 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed,  or :? for other 
options

CL-USER 11 : 1 > :c 3

Enter a form to be evaluated: "Brussels"
"Brussels"

CL-USER 12 > (person-address *pascal*)
"Brussels"


I hope this gives you the basic idea. Common Lisp development 
environments come with more convenient means to do these things (i.e., 
to add and change definitions on the go).


Pascal

-- 
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++
From: Pascal Bourguignon
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <8764snlmn6.fsf@thalassa.informatimago.com>
"bradb" <··············@gmail.com> writes:

> I hear lots about how one can interactively debug a Lisp program as it
> is running.  I take this to mean that I can manipulate data structures
> and modify functions as my program is running its main loop.  Or are
> people just meaning the REPL when they say interactive?
> If it is possible to tinker with a running image, how does one go about
> doing it?  Or is this not a topic for a beginner :)

The beginner can do this:


[22]> (defun next (i) (1+ i))

NEXT
[23]> (loop
    :for i = 0 then (next i)
    :while (<= 0 i)
    :do (print i))

0 
1 
2 
3 
...
10572 
10573 
10574 
10575 
** - Continuable Error
EVAL: User break
If you continue (by typing 'continue'): Continue execution
The following restarts are also available:
ABORT          :R1      ABORT
Break 1 [24]> (defun next (i) (1- i))
NEXT
Break 1 [24]> continue

10574 
10573 
10572 
10571 
10570 
...
3 
2 
1 
0 
NIL
[25]> 

Et hop!  One bug corrected at run-time!


With an implementation that support threads, you can even redefine the
function without breaking into the debugger, with a REPL in another
thread.



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.
From: Julian Squires
Subject: Re: Interactive debugging tips...
Date: 
Message-ID: <rNudnbnVIuSdvqTeRVn-ig@rogers.com>
On 2005-09-26, bradb <··············@gmail.com> wrote:
> If it is possible to tinker with a running image, how does one go about
> doing it?  Or is this not a topic for a beginner :)

Frequently I run a program which creates its own window and has
graphical output and interaction there, and at the same time I change
parts of the source and update them with C-c C-c in SLIME, and inspect
and modify things from the REPL.  Try things in the debugger, too.  It's
pretty easy to get this sort of stuff working.

Cheers.

-- 
Julian Squires