From: rif
Subject: Special variables question
Date: 
Message-ID: <wj0acu6mzkk.fsf@five-percent-nation.mit.edu>
In my implemetation of suffix trees, I tried to use a special variable
to control dispatch in print-object.  It didn't work as I expected;
I've simplified an example that shows what I'm confused about.
Suppose I load the following file:

(defstruct index-holder string index)
(defstruct index i)

(defvar *index-string* nil)

(defun print-index-string-set (i str)
  (format str "#<index: ~A>"
          (subseq *index-string* i)))

(defun print-index-string-not-set (i str)
  (format str "#<index: ~A>" i))

(defmethod print-object ((i-h index-holder) (str stream))
  (let ((*index-string* (index-holder-string i-h)))
    (format str "#<index-holder(~A), ~A>"
            (index-holder-string i-h)
            (index-holder-index i-h))))

(defmethod print-object ((i index) (str stream))
  (if *index-string*
      (print-index-string-set (index-i i) str)
      (print-index-string-not-set (index-i i) str)))

The following behavior is what I don't understand:

CL-USER> (defparameter *i* (make-index :i 3))
*I*
CL-USER> (defparameter *i-h* (make-index-holder :string "foobar" :index *i*))
*I-H*
CL-USER> *i-h*
#<index-holder(foobar), #<index: bar>>
CL-USER> *i*
#<index: 3>
CL-USER> (let ((*index-string* "foobar")) *i*)
#<index: 3>
CL-USER> (setf *index-string* "foobar")
"foobar"
CL-USER> *i*
#<index: bar>

In particular, why does the variant with the let seem to fail to bind
the special variable?  I've read Gat's "Idiot's Guide" several times
now, and I'd expect 

(let ((*index-string* "foobar")) *i*) to print #<index: bar>.

Can anyone explain?


Cheers,

rif

From: Frode Vatvedt Fjeld
Subject: Re: Special variables question
Date: 
Message-ID: <2hy8hqzmb7.fsf@vserver.cs.uit.no>
rif <···@mit.edu> writes:

> (let ((*index-string* "foobar")) *i*) to print #<index: bar>.
>
> Can anyone explain?

Compare these forms:

  (print (let ((*index-string* "foobar")) *i*))

and

  (let ((*index-string* "foobar")) (print *i*))


Now, consider what happens when you type

  (let ((*index-string* "foobar")) *i*)

in the REPL.

-- 
Frode Vatvedt Fjeld
From: rif
Subject: Re: Special variables question
Date: 
Message-ID: <wj0hdob3919.fsf@geskekelud.mit.edu>
Thanks to everyone who replied!  I get it now.

rif
From: Thomas A. Russ
Subject: Re: Special variables question
Date: 
Message-ID: <ymiis8t8nn4.fsf@sevak.isi.edu>
rif <···@mit.edu> writes:

> CL-USER> *i*
> #<index: 3>
> CL-USER> (let ((*index-string* "foobar")) *i*)
> #<index: 3>
> CL-USER> (setf *index-string* "foobar")
> "foobar"
> CL-USER> *i*
> #<index: bar>
> 
> In particular, why does the variant with the let seem to fail to bind
> the special variable?  I've read Gat's "Idiot's Guide" several times
> now, and I'd expect 
> 
> (let ((*index-string* "foobar")) *i*) to print #<index: bar>.
> 
> Can anyone explain?

What you want, in order to get the behavior you expect, is

 (let ((*index-string* "foobar"))
  (print *i*))

You want to make sure that the printing takes place within the scope of
the LET binding.  By using the top-level printer, it is too late.  What
happens is that you are effectively doing this:

(print (let ((*index-string* "foobar")) *i*))

In other words, the LET returns the value *i*, which is then printed.
But the printing happens outside the scope of the LET.

BTW, if you execute 
 (let ((*index-string* "foobar"))
  (print *i*))

you will get to see both printed versions, one from the explicit
PRINT inside the LET and the other from the listener's PRINT of
the returned value (since PRINT returns the object it printed).

#<index: bar>
#<index: 3>


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Alan Crowe
Subject: Re: Special variables question
Date: 
Message-ID: <86acu5v81m.fsf@cawtech.freeserve.co.uk>
rif pondered:
> In particular, why does the variant with the let seem to fail to bind
> the special variable?  I've read Gat's "Idiot's Guide" several times
> now, and I'd expect 
>
> (let ((*index-string* "foobar")) *i*) to print #<index: bar>.

I think I see what is confusing you. The core of the problem
can be illustrated by playing with *print-base*

(let ((*print-base* 2)) (format nil "~A" 15)) => "1111"
Binary as expected.

(let ((*print-base* 2)) 15) => 15 
Still decimal!

You can think of successive stages of READ-EVAL-PRINT as
working like this:

one (print (eval (read-from-string
	           "(let ((*print-base* 2))
                      (format nil \"~A\" 15))")))

two (print (eval (let ((*print-base* 2))
		   (format nil "~A" 15))))

three (print (let ((*print-base* 2))
		(eval (format nil "~A" 15))))

four (print (let ((*print-base* 2)) "1111"))

five (print "1111")

six "1111"

and for the other case

one (print (eval (read-from-string "(let ((*print-base* 2)) 15)"))) 

two (print (eval (let ((*print-base* 2)) 15)))

three (print (let ((*print-base* 2)) (eval 15)))

four (print (let ((*print-base* 2)) 15))

five (print 15)

six 15

It is only eval that "goes inside" forms, evaling the
arguments to functions so that the functions get applied
to the values of their arguments. The PRINT in the
READ-EVAL-PRINT loop waits outside for EVAL to yield the
final result of the computation.

I think your confusion is taking

(print (let ((*print-base* 2)) 15))

and mentally pushing the PRINT inside

(let ((*print-base* 2)) (print 15))
=> 1111
   15

but you only get a PRINT inside the dynamic extent of
the LET if you type one in yourself. The implicit PRINT in
the REPL is always of the final result.

Alan Crowe
Edinburgh
Scotland