[comp.lang.lisp] about EVAL

mnjafar@wsuiar.uucp (06/05/90)

  I am a newcomer to lisp, so forgive my ignorance. I ran the
test programs shown below on three different machines with
Common Lisp. The results of the tests are shown below. Does
anyone out there know the answer to why Eval behaves in the way
it does. I looked in Guy Steele's book, but did not find an answer,
maybe I don't know where to look . What exactly is supposed  to
happen when I issue an (eval '(setq i j)) inside a block ?


The first test
---------------------------------------------------
;Test1.lsp
;
(defun strange()
 (let (j i xpr)
  (setq i 12)
  (setq xpr '(setq j i))
  (format t " ~% The value of i inside the function is : ~a~%" i)
  (format t " ~% The value of xpr inside the function is : ~a~%" xpr)
  (eval xpr)
  (format t " ~% The value of j inside the function is :~a~%" j)
 )
)
(strange)
---------------------------------------------------


The second test
---------------------------------------------------
;Test2.lsp
;
(defun strange()
 (let (j i xpr)
  (setq i 12)
  (setq xpr '(setq j i))
  (format t " ~% The value of i inside the function is : ~a~%" i)
  (format t " ~% The value of xpr inside the function is : ~a~%" xpr)
  (eval xpr)
  (format t " ~% The value of j inside the function is :~a~%" j)
    j
 )
)
(setq i 13)
(format t   " ~% The value of i outside the function is : ~a~%" i)
(strange)
----------------------------------------------------



 The results obtained

Machine: VAX 8650 running VMS 5.2
         Vax Lisp  V 2.2

Test       |     Error Message or value of j
---------------------------------------------
test1      |     symbol has no value : I
test2      |     nil




Machine: SUN 
         Sun Common Lisp, development environment 3.0.2

Test       |     Error Message or value of j
---------------------------------------------
test1      |     the symbol I has no global value
test2      |     nil



Machine: PC/AT compatible
         Golden Common Lisp Version 1.01

Test       |     Error Message or value of j
---------------------------------------------
test1      |     12
test2      |     12



Mohammad Jafar
mnjafar@wsuiar.wsu.ukans.edu

lou@atanasoff.rutgers.edu (Lou Steinberg) (06/08/90)

In article <200.266aae50@wsuiar.uucp> mnjafar@wsuiar.uucp writes:

> I looked in Guy Steele's book, but did not find an answer,
> maybe I don't know where to look . What exactly is supposed  to
> happen when I issue an (eval '(setq i j)) inside a block ?

See the definition of eval (p. 490 of 2nd edition of Steele):

    eval form

    The form is evaluated in the current lexical environment and a null
    lexical environment.

The term "null lexical environment" means that the eval does NOT take
place in the lexical scope where the eval appears.  Thus, to simplify
your example,

(defun strange ()
  (let (i j)
       (eval '(setq j i))))

is equivalent to

(defun strange ()
  (let (i j)
       (strange1)))

(defun strange1 ()
  (setq j i))

Note that the value of j your example code prints is for the binding
INSIDE strange, which is unaffected by the setq of the top-level value
done by the eval, and thus is still its initial value, NIL.

I assume the language was defined this way because, in the general
case, the form to be evaled may not be available until run time, but
an efficient compiler may want to compile things in such a way that at
runtime it is hard to figure out, e.g., that local variable i is
currently being stored in register D3.  Without this information, of
course, the code to be evaled could not be properly interpretted (or
compiled).  Yes, this information could be kept somewhere, but the
question is whether this kind of runtime access to the lexical
environment would be worth the overhead needed to provide it.

So, by your tests, Golden Common Lisp Version 1.01 is not a correct
implementation of lexical scoping.  (This may have been corrected in
later versions.)  The results returned by the other two
implementations are correct.
-- 
					Lou Steinberg

uucp:   {pretty much any major site}!rutgers!aramis.rutgers.edu!lou 
arpa:   lou@cs.rutgers.edu

jeff@aiai.ed.ac.uk (Jeff Dalton) (06/08/90)

In article <200.266aae50@wsuiar.uucp> mnjafar@wsuiar.uucp writes:
>
>  I am a newcomer to lisp, so forgive my ignorance. I ran the
>test programs shown below on three different machines with
>Common Lisp. The results of the tests are shown below. Does
>anyone out there know the answer to why Eval behaves in the way
>it does. I looked in Guy Steele's book, but did not find an answer,
>maybe I don't know where to look.

In CLtL, you need to look at

    3     Scope and Extent
    5.1.2 Variables
    7.1.1 Reference: 1st paragraph
    7.5   Establishing New Variable Bindings
    9.2   Declaration specifiers: the part on SPECIAL
    20.1  Run-Time Evaluation of Forms: EVAL  

Pay attention to all the places where it talks about the distinction
between special variables and other kinds.  Then note that EVAL
evaluates an expression in the current dynamic environment and
a null lexical environment.  Note too that global variables are
the "outermost" special variables.

Now suppose we do

   (setq x 'global-x)

Then consider the following examples.  They just refer to values
rather than use SETQ because it's simpler.  Where the local value
is obtained, a SETQ would set the local value; and similarly for
the global value.

   (let ((x 'local-x))
     x)                           ==>  local-x

The LET establishes a _lexical_ variable X and gives it the value
LOCAL-X.

   (let ((x 'local-x))
     (eval 'x))                   ==>  global-x

The LET works as before, but since EVAL uses a null lexical
environment it does not "see" the local X.

   (let ((x 'local-x))
     (declare (special x))
     x)                           ==>  local-x

Here the LET establishes a _special_ variable X, because of the
declaration.

   (let ((x 'local-x))
     (declare (special x))
     (eval 'x))                   ==>  local-x

This is because EVAL uses the _current_ dynamic (ie, special variable)
environment.

Ok, now let's try this one:

   (setq x 'x0 y 'y0)

   (defun test ()

     (let (x y)
       (declare (special y))

       (setq x 'x1 y 'y1)
       (format t "~&X = ~S; Y = ~S~%" x y)

       (eval '(setq x 'x2 y 'y2))
       (format t "~&X = ~S; Y = ~S~%" x y))

     (format t "~&X = ~S; Y = ~S~%" x y))

After this, "(test)" will print:

   X = x1; Y = y1
   X = x1; Y = y2
   X = x2; Y = y0

What happens when test is called is:

  1. The LET sets up local lexical variable X and a local special
     variable Y.

  2. The SETQ sets the values of those same variables.

  3. The EVAL of SETQ sets the global (special) X, because there
     is no local one, and the local (special) Y.  Remember that
     EVAL uses the current special environment but a null lexical
     one.  So it will see only global or local special variables.

>What exactly is supposed  to happen when I issue an (eval '(setq i j))
>inside a block ?

What it is supposed to do is to set the global value of I to be
the global value of J, just as if you typed "(setq i j)" directly
to the top-level read-eval-print loop.  Actually for "global
value" I should really say something like "value of the current
binding of the special variable". 

Note, however, that in your tests you do "(setq j i)" instead.

   ;Test1.lsp

   (defun strange()
    (let (j i xpr)
     (setq i 12)
     (setq xpr '(setq j i))
     (eval xpr)
     (format t " ~% The value of j inside the function is :~a~%" j)
    )
   )

Calling (strange) should result in an error saying "I" is unbound
or has no global value (unless, of course, you've given it one
independently.

Your test2 is the same, except that you *do* give "I" a global value.
By calling EVAL on (SETQ J I), you set the global value of J to be
(in this case) 13.  The local value of J (ie, inside the function)
will be NIL, because that's what LET gives it initially.

The results for Golden Common Lisp 1.01 are incorrect.  What is
probably happening is that it is interpreting local variables
(such as those introduced by LET) as special variables.  The
SETQ given to EVAL affects such variables.  Indeed, note that
the value of J is 12 and not 13 even though in test2 you set
the global value of I to 13.

I suspect a more recent version of GCL would give results in line
with the other Common Lisps.

-- Jeff

scott@wiley.uucp (Scott Simpson) (06/09/90)

In article <200.266aae50@wsuiar.uucp> mnjafar@wsuiar.uucp writes:
>  I am a newcomer to lisp, so forgive my ignorance. I ran the
>test programs shown below on three different machines with
>Common Lisp. The results of the tests are shown below. Does
>anyone out there know the answer to why Eval behaves in the way
>it does. I looked in Guy Steele's book, but did not find an answer,
>maybe I don't know where to look . What exactly is supposed  to
>happen when I issue an (eval '(setq i j)) inside a block ?
>;Test1.lsp
>(defun strange()
> (let (j i xpr)		;j, i and xpr are nil
>  (setq i 12)
>  (setq xpr '(setq j i))
>  (format t " ~% The value of i inside the function is : ~a~%" i)
>  (format t " ~% The value of xpr inside the function is : ~a~%" xpr)
>  (eval xpr)
>  (format t " ~% The value of j inside the function is :~a~%" j)
> )
>)
>(strange)

Eval is executed in its own local environment.  The stack of execution
looks like

	|---------------------|
	|eval + environment   |___
	|---------------------|  |
	|strange + environment|  |
	-----------------------  |  Can't find i!
				 V

Since i is not in eval's environment and it is not in the global
environment you get an error.  If you change the line

(let (j i xpr) 

to

(let (j i xpr) (declare (special i))

then i is dynamically scoped and it will be found in strange's
environment.

	|---------------------|
	|eval + environment   |___
	|---------------------|  |   finds i dynamically, sets global j
	|strange + environment|<--
	-----------------------

The function strange will now completes correctly and returns

 The value of i inside the function is : 12
 The value of xpr inside the function is : (SETQ J I)
 The value of j inside the function is :NIL

Notice that j is nil.  The setq in the eval creates and sets a
global variable named j (try evaluating j after running the new
strange function with the declare). The j inside the function strange
is never set.
	If you wish to set the j inside the function, declare it
dynamically scoped also.

(let (j i xpr) (declare (special i) (special j))

The result is now

 The value of i inside the function is : 12
 The value of xpr inside the function is : (SETQ J I)
 The value of j inside the function is :12

No global j is created.

>;Test2.lsp
>(defun strange()
> (let (j i xpr)
>  (setq i 12)
>  (setq xpr '(setq j i))
>  (format t " ~% The value of i inside the function is : ~a~%" i)
>  (format t " ~% The value of xpr inside the function is : ~a~%" xpr)
>  (eval xpr)
>  (format t " ~% The value of j inside the function is :~a~%" j)
>    j
> )
>)
>(setq i 13)
>(format t   " ~% The value of i outside the function is : ~a~%" i)
>(strange)

This yielded

 The value of i inside the function is : 12
 The value of xpr inside the function is : (SETQ J I)
 The value of j inside the function is :NIL

J is still nil.  The j set by the eval was a global j.  A global i
exists now though so you only need to make j special.  Try making j
special and you get

 The value of i inside the function is : 12
 The value of xpr inside the function is : (SETQ J I)
 The value of j inside the function is :12


> The results obtained
>Machine: VAX 8650 running VMS 5.2
>         Vax Lisp  V 2.2
>Test       |     Error Message or value of j
>---------------------------------------------
>test1      |     symbol has no value : I
>test2      |     nil
>
>Machine: SUN 
>         Sun Common Lisp, development environment 3.0.2
>Test       |     Error Message or value of j
>---------------------------------------------
>test1      |     the symbol I has no global value
>test2      |     nil

These are correct.

>Machine: PC/AT compatible
>         Golden Common Lisp Version 1.01
>
>Test       |     Error Message or value of j
>---------------------------------------------
>test1      |     12
>test2      |     12

This is incorrect.
Scott Simpson    		TRW 		scott@wiley.coyote.trw.com