From: Wang Yin
Subject: How can prevent defun use global values?
Date: 
Message-ID: <m3fzhji0es.fsf@wangyin.com>
Hi, 

I'm tring to write a "object property" package that can set "property"
for an object. For example, it behaves as follows, just like property
list for symbols:

(setf a (list "good"))
(objget a 'set)   ;==> nil
(objput a 'set 2) ;==> 2
(objget a 'set)   ;==> 2
(objremprop a 'set) ;==> 2
(objget a 'set)   ;==> nil

I write the following code. I store a property list in a hash table
named objhash indexed by objects. When objget asking for a property
for an object I look up this list associated with the object and
return the value. 

It works fine. But there is a problem. If there is a global variable
named "objhash" in the toplevel. And I run
initialize-obj-prop-table. Then all the functions defined inside will
use the global "objhash" as a hashtable.

I see I should name the global one as *objhash*, but I want the inner
defun's use the lexical binding in the let block and not the global
variable. How can I do that? In Scheme inner defuns will use the local
variable by default. How can I do that with Common Lisp?

And, does anyone has better ideas about the implementation of a
"object property"?


Here is my code:

(setf objhash (make-hash-table))

(defun initialize-obj-prop-table ()
  (let ((objhash (make-hash-table)))
    (defun objget (obj prop &optional (default nil))
      (let* ((plist (gethash obj objhash))
             (tail (memq prop plist)))
        (if tail (cadr tail) default)))

    (defun objput (obj prop val)
      (let* ((plist (gethash obj objhash))
             (tail (memq prop plist)))
        (cond ((null plist)
               (setf (gethash obj objhash) (list prop val)))
              ((null tail)
               (setf (gethash obj objhash) (append (list prop val) plist)))
              (t (setf (cadr tail) val)))))

    (defun objremprop (obj prop)
      (let ((plist (gethash obj objhash)))
        (setf (gethash obj objhash) (remove-n prop plist 2))))

    (defun objplist (obj)
      (gethash obj objhash))))

(initialize-obj-prop-table)




-- 
Yin Wang,
EDA Lab,
Deparment of Computer Science and Technology,
Tsinghua University,
100084
Beijing China

From: james anderson
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <3F98D523.6B1EA5EE@setf.de>
Wang Yin wrote:
> 
> I see I should name the global one as *objhash*, but I want the inner
> defun's use the lexical binding in the let block and not the global
> variable. How can I do that? In Scheme inner defuns will use the local
> variable by default. How can I do that with Common Lisp?
> 
> And, does anyone has better ideas about the implementation of a
> "object property"?
> 

since this "reimplements" objects, it must be that it is necessary not only to
'set "property"
for an object', but to do so in manner which models an (object x context x
property) relation. in which case there would be more than one context. is
that true?

in that case, it might be better to turn the model inside-out and bind the
dictionaries to the objects index the properties by context. or perhaps to
model the relation directly. depends on the relative numbers of objects and
contexts and whether the properties and/or objects are static and/or a
constant population.

in general, it is not clear from the post, which aspect of the behaviour of
the illustrated implemention is not desired.

> Here is my code:
> 
> (setf objhash (make-hash-table))
> 
> (defun initialize-obj-prop-table ()
>   (let ((objhash (make-hash-table)))
>     (defun objget (obj prop &optional (default nil))
>       (let* ((plist (gethash obj objhash))
>              (tail (memq prop plist)))
>         (if tail (cadr tail) default)))
> 
>     (defun objput (obj prop val)
>       (let* ((plist (gethash obj objhash))
>              (tail (memq prop plist)))
>         (cond ((null plist)
>                (setf (gethash obj objhash) (list prop val)))
>               ((null tail)
>                (setf (gethash obj objhash) (append (list prop val) plist)))
>               (t (setf (cadr tail) val)))))
> 
>     (defun objremprop (obj prop)
>       (let ((plist (gethash obj objhash)))
>         (setf (gethash obj objhash) (remove-n prop plist 2))))
> 
>     (defun objplist (obj)
>       (gethash obj objhash))))
> 
> (initialize-obj-prop-table)

...
From: Wang Yin
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <m365if9j9x.fsf@wangyin.com>
james anderson <··············@setf.de> writes:

> 
> since this "reimplements" objects, it must be that it is necessary not only to
> 'set "property"
> for an object', but to do so in manner which models an (object x context x
> property) relation. in which case there would be more than one context. is
> that true?
> 
> in that case, it might be better to turn the model inside-out and bind the
> dictionaries to the objects index the properties by context. or perhaps to
> model the relation directly. depends on the relative numbers of objects and
> contexts and whether the properties and/or objects are static and/or a
> constant population.
> 
> in general, it is not clear from the post, which aspect of the behaviour of
> the illustrated implemention is not desired.


I missed a utility code here:

(defun remove-n (item list &optional (n 1) &key ((:test test) #'eql))
  "Remove n items from the list."
  (cond ((null list) nil)
        ((funcall test item (car list)) (nthcdr n list))
        (t (cons (car list) (remove-n item (cdr list) n)))))


Maybe you misunderstood me. I just want my "inner" defuns use the
hashtable objhash created by let inside initialize-obj-prop-table. But
If there is a (setf objhash (make-hash-table)), then objhash will
become "special" in CMU CL. I mean, how can I tell the defuns to
ignore the "special objhash"?



> 
> > Here is my code:
> > 
> > (setf objhash (make-hash-table))
> > 
> > (defun initialize-obj-prop-table ()
> >   (let ((objhash (make-hash-table)))
> >     (defun objget (obj prop &optional (default nil))
> >       (let* ((plist (gethash obj objhash))
> >              (tail (memq prop plist)))
> >         (if tail (cadr tail) default)))
> > 
> >     (defun objput (obj prop val)
> >       (let* ((plist (gethash obj objhash))
> >              (tail (memq prop plist)))
> >         (cond ((null plist)
> >                (setf (gethash obj objhash) (list prop val)))
> >               ((null tail)
> >                (setf (gethash obj objhash) (append (list prop val) plist)))
> >               (t (setf (cadr tail) val)))))
> > 
> >     (defun objremprop (obj prop)
> >       (let ((plist (gethash obj objhash)))
> >         (setf (gethash obj objhash) (remove-n prop plist 2))))
> > 
> >     (defun objplist (obj)
> >       (gethash obj objhash))))
> > 
> > (initialize-obj-prop-table)
> 
> ...


-- 
Yin Wang,
EDA Lab,
Deparment of Computer Science and Technology,
Tsinghua University,
100084
Beijing China
From: Fred Gilham
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <u7wuauaete.fsf@snapdragon.csl.sri.com>
The following seems to do what you want.  As far as I can tell.

Every time you call initialize-obj-prop-table, you will throw away
your old objhash table and create a new one.  I don't know if that's
what you want or not.


(defun remove-n (item list &optional (n 1) &key ((:test test) #'eql))
  "Remove n items from the list."
  (cond ((null list) nil)
        ((funcall test item (car list)) (nthcdr n list))
        (t (cons (car list) (remove-n item (cdr list) n)))))

(defun initialize-obj-prop-table ()

  (let ((objhash (make-hash-table)))

    (labels ((objget (obj prop &optional (default nil))
	       (let* ((plist (gethash obj objhash))
		      (tail (memq prop plist)))
		 (if tail (cadr tail) default)))

	     (objput (obj prop val)
	       (let* ((plist (gethash obj objhash))
		      (tail (memq prop plist)))
		 (cond ((null plist)
			(setf (gethash obj objhash) (list prop val)))
		       ((null tail)
			(setf (gethash obj objhash) (append (list prop val) plist)))
		       (t (setf (cadr tail) val)))))

	     (objremprop (obj prop)
	       (let ((plist (gethash obj objhash)))
		 (setf (gethash obj objhash) (remove-n prop plist 2))))

	     (objplist (obj)
	       (gethash obj objhash)))

      ;; Make your functions "public".
      (setf (fdefinition 'ojbget) #'objget
	    (fdefinition 'objput) #'objput
	    (fdefinition 'objremprop) #'objremprop
	    (fdefinition 'objplist) #'objplist))))

(initialize-obj-prop-table)

-- 
Fred Gilham                                     ······@csl.sri.com
"Come to me, all who labor and are heavy laden, and I will give you
rest.  Take my yoke upon you, and learn from me, for I am gentle and
lowly in heart, and you will find rest for your souls.  For my yoke
is easy, and my burden is light."               --Jesus of Nazareth
From: Wang Yin
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <m33cdcscpk.fsf@wangyin.com>
Fred Gilham <······@snapdragon.csl.sri.com> writes:

> The following seems to do what you want.  As far as I can tell.
> 
> Every time you call initialize-obj-prop-table, you will throw away
> your old objhash table and create a new one.  I don't know if that's
> what you want or not.
> 
> 
> (defun remove-n (item list &optional (n 1) &key ((:test test) #'eql))
>   "Remove n items from the list."
>   (cond ((null list) nil)
>         ((funcall test item (car list)) (nthcdr n list))
>         (t (cons (car list) (remove-n item (cdr list) n)))))
> 
> (defun initialize-obj-prop-table ()
> 
>   (let ((objhash (make-hash-table)))
> 
>     (labels ((objget (obj prop &optional (default nil))
> 	       (let* ((plist (gethash obj objhash))
> 		      (tail (memq prop plist)))
> 		 (if tail (cadr tail) default)))
> 
> 	     (objput (obj prop val)
> 	       (let* ((plist (gethash obj objhash))
> 		      (tail (memq prop plist)))
> 		 (cond ((null plist)
> 			(setf (gethash obj objhash) (list prop val)))
> 		       ((null tail)
> 			(setf (gethash obj objhash) (append (list prop val) plist)))
> 		       (t (setf (cadr tail) val)))))
> 
> 	     (objremprop (obj prop)
> 	       (let ((plist (gethash obj objhash)))
> 		 (setf (gethash obj objhash) (remove-n prop plist 2))))
> 
> 	     (objplist (obj)
> 	       (gethash obj objhash)))
> 
>       ;; Make your functions "public".
>       (setf (fdefinition 'ojbget) #'objget
> 	    (fdefinition 'objput) #'objput
> 	    (fdefinition 'objremprop) #'objremprop
> 	    (fdefinition 'objplist) #'objplist))))
> 
> (initialize-obj-prop-table)

Yeah! This is exactly what I wanted!  In Scheme I usually use several
inner define's and use a "dispatcher" to return the function objects
outside of the closure. I seems CL labels has the same effect as
Scheme's inner define.


> 
> -- 
> Fred Gilham                                     ······@csl.sri.com
> "Come to me, all who labor and are heavy laden, and I will give you
> rest.  Take my yoke upon you, and learn from me, for I am gentle and
> lowly in heart, and you will find rest for your souls.  For my yoke
> is easy, and my burden is light."               --Jesus of Nazareth


-- 
Yin Wang,
EDA Lab,
Deparment of Computer Science and Technology,
Tsinghua University,
100084
Beijing China
From: Frode Vatvedt Fjeld
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <2hhe1zhwuc.fsf@vserver.cs.uit.no>
Wang Yin <··@wangyin.com> writes:

> [..] I mean, how can I tell the defuns to ignore the "special
> objhash"?

You can't. This is why it is advised to always keep your special
variables named *foo*.

However, you can move the old symbol (and its special proclamation)
out of the way by doing (unintern 'objhash). Then make sure you don't
declare it special again. You should pretty much never have top-level
setf forms in your program.

If you want some general advice, it is highly improbable that you
really want to use defun the way you seem to be doing. Defun always
create global definitions. This has (at least) the following
consequences:

  - It is almost always pointless to have nested defuns. It's just
    semantically a very strange thing to do.

  - Any variables the function closes over will, by definition, be
    global variables. Even if they are not globally accessible. Lisp
    tradition is that it is usually smarter to acknowledge this fact
    and use a global (i.e. top-level special variable, like (defvar
    *variable* 'value)) instead. This improves the interactive aspect
    of your program.

-- 
Frode Vatvedt Fjeld
From: Wade Humeniuk
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <C%5mb.6406$EO3.2466@clgrps13>
Frode Vatvedt Fjeld wrote:

> Wang Yin <··@wangyin.com> writes:
> 
> 
>>[..] I mean, how can I tell the defuns to ignore the "special
>>objhash"?
> 
> 
> You can't. This is why it is advised to always keep your special
> variables named *foo*.

Best advice, but if you what to hack a bit then this might
be a solution.  But best advice is too really name specials
*var* and avoid the troubles.

(defvar objhash (make-hash-table))

(defun initialize-obj-prop-table ()
   (defun objhash () #.(make-hash-table))
   (defun objget (obj prop &optional (default nil))
     (let* ((plist (gethash obj (objhash)))
            (tail (memq prop plist)))
       (if tail (cadr tail) default)))

   (defun objput (obj prop val)
     (let* ((plist (gethash obj (objhash)))
            (tail (memq prop plist)))
       (cond ((null plist)
              (setf (gethash obj (objhash)) (list prop val)))
             ((null tail)
              (setf (gethash obj (objhash)) (append (list prop val) plist)))
             (t (setf (cadr tail) val)))))

   (defun objremprop (obj prop)
     (let ((plist (gethash obj (objhash))))
       (setf (gethash obj (objhash)) (remove-n prop plist 2))))

   (defun objplist (obj)
     (gethash obj (objhash))))

(initialize-obj-prop-table)

CL-USER 3 > (eq objhash (objhash))
NIL

CL-USER 4 >

or

(defun initialize-obj-prop-table ()
   (flet ((objhash () #.(make-hash-table)))
     (defun objget (obj prop &optional (default nil))
       (let* ((plist (gethash obj (objhash)))
              (tail (memq prop plist)))
         (if tail (cadr tail) default)))

     (defun objput (obj prop val)
       (let* ((plist (gethash obj (objhash)))
              (tail (memq prop plist)))
         (cond ((null plist)
                (setf (gethash obj (objhash)) (list prop val)))
               ((null tail)
                (setf (gethash obj (objhash)) (append (list prop val) plist)))
               (t (setf (cadr tail) val)))))

     (defun objremprop (obj prop)
       (let ((plist (gethash obj (objhash))))
         (setf (gethash obj (objhash)) (remove-n prop plist 2))))

     (defun objplist (obj)
       (gethash obj (objhash)))))


Wade
From: james anderson
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <3F98E4BB.C0B590DD@setf.de>
Frode Vatvedt Fjeld wrote:
> 
> Wang Yin <··@wangyin.com> writes:
> 
> > [..] I mean, how can I tell the defuns to ignore the "special
> > objhash"?
> 
> You can't. This is why it is advised to always keep your special
> variables named *foo*.
> 
> However, you can move the old symbol (and its special proclamation)
> out of the way by doing (unintern 'objhash). Then make sure you don't
> declare it special again. You should pretty much never have top-level
> setf forms in your program.
> 

? since when does a top-level setf/setq form have a special proclamation as a side-effect?

> If you want some general advice, it is highly improbable that you
> really want to use defun the way you seem to be doing. Defun always
> create global definitions. This has (at least) the following
> consequences:
> 
>   - It is almost always pointless to have nested defuns. It's just
>     semantically a very strange thing to do.
> 
>   - Any variables the function closes over will, by definition, be
>     global variables. Even if they are not globally accessible. Lisp
>     tradition is that it is usually smarter to acknowledge this fact
>     and use a global (i.e. top-level special variable, like (defvar
>     *variable* 'value)) instead. This improves the interactive aspect
>     of your program.
> 

well, there is the view, that, given the object - closure duality, the effect
is to implement singletons.

...
From: Fred Gilham
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <u7znfqafzz.fsf@snapdragon.csl.sri.com>
> ? since when does a top-level setf/setq form have a special
> proclamation as a side-effect?

CMU Lisp.

* (setf foo 2)
Warning:  Declaring FOO special.

2
* 

It's considered a feature by some and a bug by many.  :-)

-- 
Fred Gilham   ······@csl.sri.com | I wish I could get the product I
sell or service I provide to become a human right.  Then people would
be forced to pay for it and use it.  The only drawback is that, like
schoolteachers, I probably would wind up actually doing something else.
From: Christophe Rhodes
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <sqfzhjvx5e.fsf@lambda.jcn.srcf.net>
james anderson <··············@setf.de> writes:

> Frode Vatvedt Fjeld wrote:
>> However, you can move the old symbol (and its special proclamation)
>> out of the way by doing (unintern 'objhash). Then make sure you don't
>> declare it special again. You should pretty much never have top-level
>> setf forms in your program.
>
> ? since when does a top-level setf/setq form have a special
> proclamation as a side-effect?

Which part of "undefined behaviour" is hard to understand?  I believe
CMUCL does a special proclamation as a side-effect, and it is quite
within its rights to do so.

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: james anderson
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <3F98EB82.D38862AE@setf.de>
Christophe Rhodes wrote:
> 
> james anderson <··············@setf.de> writes:
> 
> > Frode Vatvedt Fjeld wrote:
> >> However, you can move the old symbol (and its special proclamation)
> >> out of the way by doing (unintern 'objhash). Then make sure you don't
> >> declare it special again. You should pretty much never have top-level
> >> setf forms in your program.
> >
> > ? since when does a top-level setf/setq form have a special
> > proclamation as a side-effect?
> 
> Which part of "undefined behaviour" is hard to understand?

don't ask me. i'm not the one who didn't understand it. so far as i could
follow the posts, the uncertainty as to the actual effect of the specific
instance of a setf form on the special status of the specific variable resides
with the cmucl user.

...
From: Frode Vatvedt Fjeld
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <2hd6cnhvts.fsf@vserver.cs.uit.no>
james anderson <··············@setf.de> writes:

> ? since when does a top-level setf/setq form have a special
> proclamation as a side-effect?

I don't know, but I thought that's what the OP said his system did. I
believe the effect of setting an undefined variable is undefined, so
pretty much anything would be legal for an implementation to do.

-- 
Frode Vatvedt Fjeld
From: Thomas A. Russ
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <ymik76qfuus.fsf@sevak.isi.edu>
Frode Vatvedt Fjeld <······@cs.uit.no> writes:

> 
> james anderson <··············@setf.de> writes:
> 
> > ? since when does a top-level setf/setq form have a special
> > proclamation as a side-effect?
> 
> I don't know, but I thought that's what the OP said his system did. I
> believe the effect of setting an undefined variable is undefined, so
> pretty much anything would be legal for an implementation to do.

Correct.  I believe CMUCL will proclaim the variable special.  As far as
I know, it is the only Common Lisp implementation that does this.  The
others just use a local treatment of the variable as special.

I don't know if it is possible to control this behavior of CMUCL through
the use of a magic switch or variable.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Adam Warner
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <pan.2003.10.24.08.56.44.835993@consulting.net.nz>
Hi james anderson,

> ? since when does a top-level setf/setq form have a special proclamation
> as a side-effect?

Since before I disabled it in CMUCL's .cmucl-init.lisp:
(setf ext:*top-level-auto-declare* nil)

* (describe '*top-level-auto-declare*)

*top-level-auto-declare* is an external symbol in the EXTENSIONS package.
It is a special variable; its value is nil.
Special documentation:
  This variable controls whether assignments to unknown variables at top-level
   (or in any other call to EVAL of SETQ) will implicitly declare the variable
   SPECIAL.  These values are meaningful:
     :WARN  -- Print a warning, but declare the variable special (the default.)
      T     -- Quietly declare the variable special.
      NIL   -- Never declare the variable, giving warnings on each use.

Regards,
Adam
From: james anderson
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <3F98F0DD.571F6272@setf.de>
Adam Warner wrote:
> 
> Hi james anderson,
> 
> > ? since when does a top-level setf/setq form have a special proclamation
> > as a side-effect?
> 
> Since before I disabled it in CMUCL's .cmucl-init.lisp:
> (setf ext:*top-level-auto-declare* nil)

hey. it's nice that one can disable the extension. might we also discuss
whether a default setting of :warn or t does much to further the portability
of conforming programs?

...
From: Adam Warner
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <pan.2003.10.24.10.48.46.212182@consulting.net.nz>
Hi james anderson,

>> > ? since when does a top-level setf/setq form have a special
>> > proclamation as a side-effect?
>> 
>> Since before I disabled it in CMUCL's .cmucl-init.lisp: (setf
>> ext:*top-level-auto-declare* nil)
> 
> hey. it's nice that one can disable the extension. might we also discuss
> whether a default setting of :warn or t does much to further the
> portability of conforming programs?

It's my understanding that no conforming program can setf an undefined
place so CMUCL's default behaviour for "assignments to unknown variables"
does not affect the portability of conforming programs.

As stated in 1.5.2 of the HyperSpec, "Conforming code shall not depend on
the consequences of undefined or unspecified situations."

Regards,
Adam
From: james anderson
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <3F9909AA.DA0767B9@setf.de>
Adam Warner wrote:
> 
> Hi james anderson,
> 
> >> > ? since when does a top-level setf/setq form have a special
> >> > proclamation as a side-effect?
> >>
> >> Since before I disabled it in CMUCL's .cmucl-init.lisp: (setf
> >> ext:*top-level-auto-declare* nil)
> >
> > hey. it's nice that one can disable the extension. might we also discuss
> > whether a default setting of :warn or t does much to further the
> > portability of conforming programs?
> 
> It's my understanding that no conforming program can setf an undefined
> place

which is why a default setting of t does not further portability.

>    so CMUCL's default behaviour for "assignments to unknown variables"
> does not affect the portability of conforming programs.

once they are know to conform.

> 
> As stated in 1.5.2 of the HyperSpec, "Conforming code shall not depend on
> the consequences of undefined or unspecified situations."

all very true. all very correct. but not to the point. conforming programs do
not write themselves.

a _default value of t_ for ext:*top-level-auto-declare* is the same kind of
"useful thing" as a default definition for common-lisp-user which takes
purposeful advantage of the permission to use implementation-specific
packages, or an implementation of make-package/defpackage which takes
purposeful advantage of the permission to supply implementation-specific
defaults for the used package list. 

no matter how purposeful, as a general rule, any time, as a consequence of its
default configuration, an implementation does more than the standard requires
it to do, it hinders the process of writing conforming programs rather than
furthering it.

...
From: Christophe Rhodes
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <sqn0bqvq14.fsf@lambda.jcn.srcf.net>
james anderson <··············@setf.de> writes:

> Adam Warner wrote:
>> It's my understanding that no conforming program can setf an undefined
>> place
>
> which is why a default setting of t does not further portability.

The default setting is not T.  The default setting gives the user a
nice, loud warning.

Maybe you would also care to review past mailing list discussions on
this very issue?

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: james anderson
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <3F99141C.4ADC0AD2@setf.de>
Christophe Rhodes wrote:
> 
> james anderson <··············@setf.de> writes:
> 
> > Adam Warner wrote:
> >> It's my understanding that no conforming program can setf an undefined
> >> place
> >
> > which is why a default setting of t does not further portability.
> 
> The default setting is not T.  The default setting gives the user a
> nice, loud warning.
> 
> Maybe you would also care to review past mailing list discussions on
> this very issue?

as i noted earlier, i was not uncertain as to the effect of the toplevel setf
form. it was a cmucl user who apparently did not make the connection between
the nice loud warning and the consequence for the binding within the function definitions.

...
From: Adam Warner
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <pan.2003.10.24.11.35.12.477769@consulting.net.nz>
Hi Christophe Rhodes,

> The default setting is not T.  The default setting gives the user a
> nice, loud warning.

My guess is people find this behaviour useful when testing code in the
REPL? I do find writing defparameter tedious.

Regards,
Adam
From: Christophe Rhodes
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <sqad7qvo8t.fsf@lambda.jcn.srcf.net>
Adam Warner <······@consulting.net.nz> writes:

> Hi Christophe Rhodes,
>
>> The default setting is not T.  The default setting gives the user a
>> nice, loud warning.
>
> My guess is people find this behaviour useful when testing code in the
> REPL? I do find writing defparameter tedious.

Beats me.  I don't like it at all... but I'm hardly a great REPL user,
in any case :-)

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Adam Warner
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <pan.2003.10.24.11.32.15.587000@consulting.net.nz>
Hi james anderson,

> no matter how purposeful, as a general rule, any time, as a consequence
> of its default configuration, an implementation does more than the
> standard requires it to do, it hinders the process of writing conforming
> programs rather than furthering it.

I agree. And I have no objection to ext:*top-level-auto-declare* being
changed to default to nil.

Regards,
Adam
From: james anderson
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <3F98E2D9.5D7F99A3@setf.de>
Wang Yin wrote:
> 
> james anderson <··············@setf.de> writes:
> 
> >
> > since this "reimplements" objects, it must be that it is necessary not only to
> > 'set "property"
> > for an object', but to do so in manner which models an (object x context x
> > property) relation. in which case there would be more than one context. is
> > that true?
> >
> > in that case, it might be better to turn the model inside-out and bind the
> > dictionaries to the objects index the properties by context. or perhaps to
> > model the relation directly. depends on the relative numbers of objects and
> > contexts and whether the properties and/or objects are static and/or a
> > constant population.
> >
> > in general, it is not clear from the post, which aspect of the behaviour of
> > the illustrated implemention is not desired.
> 
> I missed a utility code here:
> 
> (defun remove-n (item list &optional (n 1) &key ((:test test) #'eql))
>   "Remove n items from the list."
>   (cond ((null list) nil)
>         ((funcall test item (car list)) (nthcdr n list))
>         (t (cons (car list) (remove-n item (cdr list) n)))))

ok, but that does not help me to better understand the problem.
> 
> Maybe you misunderstood me.

evidently.

>   I just want my "inner" defuns use the
> hashtable objhash created by let inside initialize-obj-prop-table. But
> If there is a (setf objhash (make-hash-table)), then objhash will
> become "special" in CMU CL.

hmm. there was no mention of either a declaration for objhash, or a
definition, i was not aware that the setf should declare it as special.

>   I mean, how can I tell the defuns to
> ignore the "special objhash"?

if there was one, but the intent was that the let ((objhash ...) produce a
lexical binding, then simply eliminate the global definition/declaration for objhash.

>
From: Jon S. Anthony
Subject: Re: How can prevent defun use global values?
Date: 
Message-ID: <m3llra3dxa.fsf@rigel.goldenthreadtech.com>
Wang Yin <··@wangyin.com> writes:


> (setf objhash (make-hash-table))

This is not guaranteed to work if objhash has not been previously
defined (say by a def(parameter|var), though most implementations will
implicitly do this for you (and issue a warning).

> I see I should name the global one as *objhash*, but I want the inner
> defun's use the lexical binding in the let block and not the global
> variable.

Note they are using the binding of objhash in the let - it's just that
this is a dynamic rebinding of the "global" (really dynamic) objhash.


> How can I do that? In Scheme inner defuns will use the local
> variable by default. How can I do that with Common Lisp?
...
> (defun initialize-obj-prop-table ()
>   (let ((objhash (make-hash-table)))
>     (defun objget (obj prop &optional (default nil))
>       (let* ((plist (gethash obj objhash))
>              (tail (memq prop plist)))
>         (if tail (cadr tail) default)))
>...

First, the objhash binding here is not "local" - it really refers to
the "global" objhash.

Second, the defuns inside the let _do_ use this binding when called.
This can be extremely useful in certain problems/contexts.  But in
order to keep things like this straight, the convention is to always
name "global" variables with the convention *your-name-here*, so that
if you want a new lexical binding you never use the "*" characters on
both sides of the name and you don't inadvertently use a "global".

Third, defuns are always global in visibility.  If you really want
_local_ nested functions use flet (analogous to let) or labels
(analogous to let*), but then they are _not_ visible outside the scope
of the containing function.


It's not clear in your case just what it is you really want to do.
Just looking at the code and your description, it may be that you
don't really even want the "outer" *objhash*, since you are returning
a closure over the lexical variable objhash - which will be persistent
- and it looks like you want the "accessors" to be globably visible.


For example:

;; "global" *objhash* is gone


(defun initialize-obj-prop-table ()
  (let ((objhash (make-hash-table)))
    (defun objget (obj prop &optional (default nil))
      (let* ((plist (gethash obj objhash))
             (tail (memq prop plist)))
        (if tail (cadr tail) default)))
...
    (defun objplist (obj)
      (gethash obj objhash))))

(initialize-obj-prop-table)

You now have a new closure and your accessors will reference the
_lexical_ (local) objhash they were defined over.  You can say

(objget my-obj :my-prop)

somewhere (after setting up my-obj of course) and you will be dealing
with "current" properties of my-obj.  If you call
initialize-obj-prop-table again, it will blow all these away and start
from scratch.


/Jon

p.s.  It might make more sense to put a property table as an attribute
of each object.