From: david
Subject: newbie structure problem
Date: 
Message-ID: <pan.2006.03.14.00.04.20.552545@earthlink.net>
hello, i am a lisp newbie and i have made this code:

(defstruct location contents)
(defstruct thing location)
(setf room1 (make-location))
(setf thing-a (make-thing))
(setf thing-b (make-thing))
(setf (location-contents room1) thing-a)
(push thing-b (location-contents room1))

now i have my thing-a and thing-b in the contents slot of room1.
my question is how can i delete a thing from the room contents?
thanks in advance for any help.
david

From: jayessay
Subject: Re: newbie structure problem
Date: 
Message-ID: <m38xrd3l95.fsf@rigel.goldenthreadtech.com>
david <·····@earthlink.net> writes:

> hello, i am a lisp newbie and i have made this code:
> 
> (defstruct location contents)
> (defstruct thing location)
> (setf room1 (make-location))
> (setf thing-a (make-thing))
> (setf thing-b (make-thing))


> (setf (location-contents room1) thing-a)

I don't know what you are really up to, but I would guess you really
want this to be

(push thing-a (location-contents room1))

> now i have my thing-a and thing-b in the contents slot of room1.
> (push thing-b (location-contents room1))

The way you originally have it, after this you will have a dotted
pair, not a proper list.  You almost certainly want a proper list
(which using push twice will give you here).

If you have a proper list, then

> my question is how can i delete a thing from the room contents?

see remove and/or delete.  You will also need some way to identify a
THING instance, i.e., you will (almost certainly) need to add some
slot which gives you such a handle, so that you can tell remove/delete
what you wish to get rid of.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: david
Subject: Re: newbie structure problem
Date: 
Message-ID: <pan.2006.03.14.00.31.03.306237@earthlink.net>
On Mon, 13 Mar 2006 19:47:34 -0500, jayessay wrote:

> I don't know what you are really up to, but I would guess you really
> want this to be
> 
> (push thing-a (location-contents room1))
> 
>> now i have my thing-a and thing-b in the contents slot of room1.
>> (push thing-b (location-contents room1))
> 
> The way you originally have it, after this you will have a dotted
> pair, not a proper list.  You almost certainly want a proper list
> (which using push twice will give you here).
> 
> If you have a proper list, then
> 
>> my question is how can i delete a thing from the room contents?
> 


thanks that worked like a charm :) i assume because the slot held nil
and push added the struct to make a proper list. while the setf just
replaced nil with the structure?

> see remove and/or delete.  You will also need some way to identify a
> THING instance, i.e., you will (almost certainly) need to add some
> slot which gives you such a handle, so that you can tell remove/delete
> what you wish to get rid of.
> 
> 
> /Jon

i'm not sure what you mean here. i tried
(delete thing-a (location-contents room1)
and it worked. anyway i am trying to write a little text adventure
because i can't wait till i finish reading all my lisp texts :)
From: Alan Manuel K. Gloria
Subject: Re: newbie structure problem
Date: 
Message-ID: <1142314132.445394.122060@i40g2000cwc.googlegroups.com>
david wrote:
> thanks that worked like a charm :) i assume because the slot held nil
> and push added the struct to make a proper list. while the setf just
> replaced nil with the structure?
Yes.  'setf changes the variable you are referring to.  If you refer to
a symbol, it changes the variable named by that symbol at that point,
if you refer to a structure slot, it changes the slot.

>
> > see remove and/or delete.  You will also need some way to identify a
> > THING instance, i.e., you will (almost certainly) need to add some
> > slot which gives you such a handle, so that you can tell remove/delete
> > what you wish to get rid of.
> >
> >
> > /Jon
>
> i'm not sure what you mean here. i tried
> (delete thing-a (location-contents room1)
> and it worked. anyway i am trying to write a little text adventure
> because i can't wait till i finish reading all my lisp texts :)
This can happen if:
(setq thing-a (make-thing))
(setq location-b (make-location))
(add-thing-to-location thing-a location-b)
(setq thing-a (make-thing))
(add-thing-to-location thing-a location-b)
(setq thing-a nil)

now you've lost the two things.  You will (almost certainly) need to
add some slot which lets you find a thing by simply NAMING the thing.

Although you COULD use the symbol the variable is bound to as THE name,
it's not considered good programming.  Lots of little things could go
wrong - you abstract a function to use the 'thing symbol as a
parameter, say, and it turns out you named "the thing your aunt gave
you which you don't know what it is" as 'thing.  It could still get
lost....
From: Alan Crowe
Subject: Re: newbie structure problem
Date: 
Message-ID: <86slpkahbx.fsf@cawtech.freeserve.co.uk>
david <·····@earthlink.net> writes:
> i'm not sure what you mean here. i tried
> (delete thing-a (location-contents room1)
> and it worked. anyway i am trying to write a little text adventure
> because i can't wait till i finish reading all my lisp texts :)

Whoops, this is going to cause you grief.

Here are a couple of examples of this going horribly wrong:

CL-USER> (let ((a (list 1 2)))
           (print (delete 1 a))
           (print (delete 2 a))
           a)

(2) 
(1) <= one comes back from the dead

(1) <= zombie one lurches into final result

Let us swap the order

CL-USER> (let ((a (list 1 2)))
           (print (delete 2 a))
           (print (delete 1 a))
           a)

(1) 
NIL <= There that got rid of it

(1) <= Oh no! it's come back an eaten my brain!

The basic idea in Lisp is that the language defaults to sharing
structures, and you avoid structure sharing bugs by
programing in a functional style.

So you have a bag with three things in it.

CL-USER> (defvar *bag* '(book candle matches))
*BAG*

You also have a knife

CL-USER> (defvar *items* (cons 'knife *bag*))
*ITEMS*

(cons 'knife *bag*)

didn't copy the data in the *bag*, it just points to it.

You can persuade the REPL to show you the structure sharing

CL-USER> (write (list *items* *bag*) :circle t)
((KNIFE . #1=(BOOK CANDLE MATCHES)) #1#)

((KNIFE BOOK CANDLE MATCHES) (BOOK CANDLE MATCHES))

If you want to drop the book from the bag you can say

CL-USER> (setf *bag* (remove 'book *bag*))
(CANDLE MATCHES)

but realise that *items* still shows 
(KNIFE BOOK CANDLE MATCHES)

This is how it is supposed to work - remove copies some or
all of the list to make a new list that doesn't have the
book in it, but the change doesn't propagate to other
variables that share structure with it.

Now sometimes that is what you want and you are pleased that
Lisp works this way, and sometimes you actually wanted the
change to propagate in which case you need to take a
different approach.

In particular you cannot use delete. Delete is for
performance tuning. When you use delete instead of remove
you still write (setf *bag* (delete 'book *bag*)), delete is
a drop in replacement for remove, but you are saying to the
compiler: I'm hurting on performance, and I know that *bag*
doesn't share structure with anything else, so rather than
allocate more memory for the copy, just re-use the memory
cells in the list. You are also saying to the compiler: I
don't care about the details, just make sure the code is
fast.

The precise form of words from

http://www.lispworks.com/documentation/HyperSpec/Body/f_rm_rm.htm#delete

is

    delete, when sequence is a list, is permitted to setf
    any part, car or cdr, of the top-level list structure in
    that sequence.

Just ignore delete until you have mastered your
implementations profiler and got the hang of adding optional
declarations.

To get changes to propage through your data structures use
defstruct of defclass to design containers and assign
functions of the old slot values to the slots:

We need bags, that are initially empty of contents
CL-USER> (defstruct bag (contents '()))
BAG

Lets fill one up as before
CL-USER> (setf *bag* (make-bag :contents '(book candle matches)))
#S(BAG :CONTENTS (BOOK CANDLE MATCHES))

We have a knife and a bag
CL-USER> (setf *items* (list 'knife *bag*))
(KNIFE #S(BAG :CONTENTS (BOOK CANDLE MATCHES)))

Do we have a book? We can write a function to search an
inhomogeneous list of things and containers for things
CL-USER> (defun got-a (item list)
           (loop for thing-or-container in list
                 thereis (check-for item thing-or-container)))
GOT-A

check-for has to recognise containers
CL-USER> (defmethod check-for (item (container bag))
           (find item (bag-contents container)))
#<STANDARD-METHOD CHECK-FOR (T BAG) {4800DDB5}>

CL-USER> (defmethod check-for (item thing)
           (eql item thing))
#<STANDARD-METHOD CHECK-FOR (T T) {4807F55D}>

Try it out
CL-USER> (got-a 'knife *items*)
T
CL-USER> (got-a 'book *items*)
BOOK

Mixed paradigm programming - assign to a slot in a structure
or object in an imperative style. Compute the new contents
in a functional style
CL-USER> (setf (bag-contents *bag*)
               (remove 'book
                       (bag-contents *bag*)))
(CANDLE MATCHES)

Now the change has propagated
CL-USER> (got-a 'book *items*)
NIL
CL-USER> (describe *items*)
(KNIFE #S(BAG :CONTENTS #)) is a CONS.

; No value

Notice that the water is already quite deep. 
What is an item? What is a container?

CL-USER> (got-a 'bag *items*)
NIL

The code that I have sketched says that a container is not
itself an item. What happens when you drop a bag? Presumably
you implicitly drop the contents. The code I've sketched
will do that automatically.

If you are interested in writing a text adventure as a
vehicle of learning CL you must check out Casting Spels by
Conrad Barski

http://www.lisperati.com/casting.html

Alan Crowe
Edinburgh
Scotland
From: Simon Brooke
Subject: Re: newbie structure problem
Date: 
Message-ID: <bb4le3-2hr.ln1@gododdin.internal.jasmine.org.uk>
in message <······························@earthlink.net>, david
(······@earthlink.net') wrote:

> On Mon, 13 Mar 2006 19:47:34 -0500, jayessay wrote:
> 
>> I don't know what you are really up to, but I would guess you really
>> want this to be
>> 
>> (push thing-a (location-contents room1))
>> 
>>> now i have my thing-a and thing-b in the contents slot of room1.
>>> (push thing-b (location-contents room1))
>> 
>> The way you originally have it, after this you will have a dotted
>> pair, not a proper list.  You almost certainly want a proper list
>> (which using push twice will give you here).
>> 
>> If you have a proper list, then
>> 
>>> my question is how can i delete a thing from the room contents?

This is Portable Standard Lisp, not Common Lisp. The target is the thing
to be deleted; objs is a collection of containers in one of which it may
exist. Any container, may, obviously, contain other containers (and a
room is treated as being a container).

(de UnPack (target objs)
       (cond
          ((null objs) nil)     ;; haven't found it, don't have anything left
                                ;; to search -> return nil
          ((member target (ContentsOf (car objs)))
                                ;; if it's in the first container...
             (put
                (car objs)
                'contents
                (Remove target (ContentsOf (car objs))))
                                ;; set the contents of that container to be
                                ;; it's contents less the target object...
             target)            ;; and return the target to say we succeeded
          (t                    ;; otherwise, we've still got stuff to search.
             (UnPack            ;; recurse...
                target
                (append         ;; adding the contents of the first container
                                ;; (if any) to the rest of the containers
                  (ContentsOf (car objs)) 
                  (cdr objs)))) ))

Things can only be put into containers provided there's sufficient room:

(de WillFit (object container)
       (let
          (room)
          (cond
             ((lessp
                 (setq room
                    (apply
                       'plus
                       (cons
                          (SizeOf object)
                          (mapcar
                             (ContentsOf container)
                             '(lambda (o) (get o 'size)))) ))
                 (SizeOf container))
                (idifference (SizeOf container) room)))))

-- 
·····@jasmine.org.uk (Simon Brooke) http://www.jasmine.org.uk/~simon/

        ;; Perl ... is the Brittney Spears of programming - easily accessible
        ;; but, in the final analysis, empty of any significant thought
                                ;; Frank Adrian on Slashdot, 21st July 2003
From: Pascal Bourguignon
Subject: Re: newbie structure problem
Date: 
Message-ID: <87acbtkhbe.fsf@thalassa.informatimago.com>
david <·····@earthlink.net> writes:

> hello, i am a lisp newbie and i have made this code:
>
> (defstruct location contents)
> (defstruct thing location)
> (setf room1 (make-location))
> (setf thing-a (make-thing))
> (setf thing-b (make-thing))
> (setf (location-contents room1) thing-a)
> (push thing-b (location-contents room1))
>
> now i have my thing-a and thing-b in the contents slot of room1.
> my question is how can i delete a thing from the room contents?


(location-contents room1) 
--> (#S(THING :LOCATION NIL) . #S(THING :LOCATION NIL))

Note how you don't have a list in (location-contents room1).

Since you first put an atom in  (location-contents room1), with:
 (setf (location-contents room1) thing-a)
then you pushed another atom on the same place with:
 (push thing-b (location-contents room1))
you get a dotted-list:
 (#S(THING :LOCATION NIL) . #S(THING :LOCATION NIL))

Well, since there are only two items in this dotted-list, it's exactly
one cons cell.

In Common Lisp, the various pre-existing functions to process lists,
and in particular to delete elements from lists, don't work on
dotted-lists or cons cells. Only on proper lists.

What do you want to do?

Do you want the contents slot of locations to hold either a thing, or
a cons holding two things, and have all the code that use it test
carefully whether it's an atom or a cons of two atoms?

Or do you want the contents slot of locations to hold a proper list of
things, be it 0, 1, or more?


In the former case, you'd have to implement your own "delete"
function. Something like:

  (defun delete-from-location (location thing)
    (setf (location-contents location)
          (cond ((eql thing (location-contents location))
                 nil)
                ((eql thing (car (location-contents location))) 
                 (cdr (location-contents location)))
                ((eql thing (cdr (location-contents location))) 
                 (car (location-contents location)))
                (t
                 (location-contents location)))))



But in anycase, what you should do is to ABSTRACT!

That is, instead of accessing directly the location-contents as you do
here, inconsistenly, not knowing what you're doing:

> (setf (location-contents room1) thing-a)
> (push thing-b (location-contents room1))

You should write a function to add a thing to a location, and a
function to remove a thing from a location:

(defun add-thing-to-location (thing location)
    ...)

(defun remove-thing-from-location (thing location)
    ...)


The implementation of these function is TOTALLY IRRELEVANT.
Now you can write:

(defstruct location contents)
(defstruct thing location)
(defparameter room1 (make-location))
(defparameter thing-a (make-thing))
(defparameter thing-b (make-thing))

(add-thing-to-location thing-a room1)
(add-thing-to-location thing-b room1)
(remove-thing-from-location thing-a room1)
;; ...

See?  It works! 




So, now, assuming you want to be able to put more than two things to a
location, you can implement them as:

(defun add-thing-to-location (thing location)
    (pushnew thing (location-contents location)))

(defun remove-thing-from-location (thing location)
    (setf (location-contents location)
          (delete thing (location-contents location)))
    thing)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay
From: david
Subject: Re: newbie structure problem
Date: 
Message-ID: <pan.2006.03.16.12.43.38.420305@earthlink.net>
thank you all very much for your help. this is what i have 
come up with so far. later i will attempt a move function
made up of put-mob and remove-mob. then i need to figure out
how to implement time. anyway, any and all suggestions, comments,
or flames welcome and appreciated :)


(setf *print-circle* t)      ;  .emacs?         

(defstruct location                 ;  how to call this room?      
	   (description "default description")
	   (contents nil)
	   (exits nil))

(defstruct mob name location inventory)

(defvar room1 (make-location
           :exits '((north room2)(south room3))))
(defvar room2 (make-location :exits '((south room1))))
(defvar room3 (make-location :exits '((north room1))))

(defvar david (make-mob :name "david"))

(defun mob-can-go (mob)
	    (location-exits (mob-location mob)))

(defun remove-mob (mob)
   "won't work if mob-location isn't set"
	   (setf (location-contents (mob-location mob))
		    (remove mob
                       (location-contents (mob-location mob)))))

(defun put-mob (mob location)
	   (setf (mob-location mob)location)
	   (push mob (location-contents location)))
From: Pascal Bourguignon
Subject: Re: newbie structure problem
Date: 
Message-ID: <87mzfqedkg.fsf@thalassa.informatimago.com>
david <·····@earthlink.net> writes:

> thank you all very much for your help. this is what i have 
> come up with so far. later i will attempt a move function
> made up of put-mob and remove-mob. then i need to figure out
> how to implement time. anyway, any and all suggestions, comments,
> or flames welcome and appreciated :)
>
>
> (setf *print-circle* t)      ;  .emacs?         
>
> (defstruct location                 ;  how to call this room?      
> 	   (description "default description")
> 	   (contents nil)
> 	   (exits nil))
>
> (defstruct mob name location inventory)
>
> (defvar room1 (make-location
>            :exits '((north room2)(south room3))))
> (defvar room2 (make-location :exits '((south room1))))
> (defvar room3 (make-location :exits '((north room1))))

As you can see, there's a little problem here. You need to use the
symbol as an indirect pointer to the destination room.

It would be better if you modeled the rooms independently from the
association:

(defun leads (from-room from-exit to-room)
   (nsubstitute (list from-exit to-room) from-exit (location-exits from-room)))

(shadow 'room)
(defun room (description &rest exits)
   (make-location :description description :exits exits))

(defparameter *beam-down-room*
  (let ((r1 (room "a small room" 'north 'south))
        (r2 (room "a big room"   'south))
        (r3 (room "a red room"   'east)))
    (leads r1 'north r2)
    (leads r1 'south r3)
    (leads r2 'south r1)
    (leads r3 'east  r2)
    r1))
  


[218]> *BEAM-DOWN-ROOM*
#1=#S(LOCATION :DESCRIPTION "a small room" :CONTENTS NIL
      :EXITS
      ((NORTH
        #2=#S(LOCATION :DESCRIPTION "a big room" :CONTENTS NIL
              :EXITS ((SOUTH #1#))))
       (SOUTH
        #S(LOCATION :DESCRIPTION "a red room" :CONTENTS NIL
           :EXITS ((EAST #2#))))))


> (defvar david (make-mob :name "david"))
>
> (defun mob-can-go (mob)
> 	    (location-exits (mob-location mob)))
>
> (defun remove-mob (mob)
>    "won't work if mob-location isn't set"
> 	   (setf (location-contents (mob-location mob))
> 		    (remove mob
>                        (location-contents (mob-location mob)))))
>
> (defun put-mob (mob location)
> 	   (setf (mob-location mob)location)
> 	   (push mob (location-contents location)))



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
        Un chat errant
se soulage
        dans le jardin d'hiver
                                        Shiki
From: Alan Crowe
Subject: Re: newbie structure problem
Date: 
Message-ID: <86y7zakz32.fsf@cawtech.freeserve.co.uk>
Pascal Bourguignon <······@informatimago.com> writes:
> david <·····@earthlink.net> writes:
> > (defvar room1 (make-location
> >            :exits '((north room2)(south room3))))
> > (defvar room2 (make-location :exits '((south room1))))
> > (defvar room3 (make-location :exits '((north room1))))
> 
> As you can see, there's a little problem here. You need to use the
> symbol as an indirect pointer to the destination room.
> 
> It would be better if you modeled the rooms independently from the
> association:
> 

The orignal design, in which place names name dynamic
variables is perfectly viable.

CL-USER> (defstruct location
           contents exits)
LOCATION
CL-USER> (defparameter *music-room*
           (make-location :contents '(fiddle bagpipes)
                          :exits '((west . *machine-room*))))
*MUSIC-ROOM*
CL-USER> (defparameter *machine-room*
           (make-location :contents '(lathe mill grinder)
                          :exits '((downstairs . *dungeon*)
                                   (east . *music-room*))))
*MACHINE-ROOM*
CL-USER> (defparameter *dungeon*
           (make-location :contents '(rack thumb-screws iron-maiden)
                          :exits '((upstairs . *machine-room*))))
*DUNGEON*
CL-USER> (defparameter *current-location* '*music-room*)
*CURRENT-LOCATION*
CL-USER> (shadow 'go)
T
CL-USER> (defun go (exit)
           (let ((passage (assoc exit (location-exits (symbol-value *current-location*)))))
             (if passage
                 (setf *current-location* (cdr passage))
                 (format t "~&You cannot leave the ~A to the ~A"
                         *current-location* exit))))
GO
CL-USER> (go 'west)
*MACHINE-ROOM*
CL-USER> (go 'downstairs)
*DUNGEON*
CL-USER> (go 'east)
You cannot leave the *DUNGEON* to the EAST
NIL
CL-USER> (go 'upstairs)
*MACHINE-ROOM*
CL-USER> (go 'east)
*MUSIC-ROOM*

I see that ability to use a global dynamic variable, and pass
around the symbol that names it, as part of CL's rapid
prototyping tool kit.

It is convenient and David should make use of it.

Another convenient built-in is the property lists of
symbols. The places accessed could be

(get 'music 'room)

(get 'machine 'room)

(get 'dungeon 'room)

The the core of the go command (dropping the error checking)
is

(setf *current-location* 
      (car (assoc exit
        (location-exits (get *current-location* 'room)))))

Out of time, posted unchecked

Alan Crowe
Edinburgh
Scotland
From: david
Subject: Re: newbie structure problem
Date: 
Message-ID: <pan.2006.03.19.13.59.51.588535@earthlink.net>
On Thu, 16 Mar 2006 14:14:55 +0100, Pascal Bourguignon wrote:


> 
> As you can see, there's a little problem here. You need to use the
> symbol as an indirect pointer to the destination room.
> 
> It would be better if you modeled the rooms independently from the
> association:
> 

if i understand you correctly, i think my whole program design
was based on using symbols as indirect pointers. is this bad?
why? i can see for myself that it gets a little complicated accessing
the properties i want. also, what is an indirect pointer as opposed
to a direct pointer? 
it seemed natural to me to make exits a property of locations but
i know nothing of program design. i think i will set my game aside
for now as i want to finish touretzky's book. and also as i am stumped
on getting move-mob to work properly. anyway here's my latest version:

(setf *print-circle* t)            
(defstruct location             
	   (description "default description")
	   (contents nil)
	   (exits nil))

(defstruct mob name location inventory)

(defvar room1 (make-location
           :exits '((north room2)(south room3))))
(defvar room2 (make-location :exits '((south room1))))
(defvar room3 (make-location :exits '((north room1))))

(defvar david (make-mob :name "david"))


(defun mob-can-go (mob)
	    (location-exits (mob-location mob)))

(defun remove-mob (mob)
   "won't work if mob-location isn't set"
	   (setf (location-contents (mob-location mob))
		    (remove mob
                       (location-contents (mob-location mob)))))

(defun put-mob (mob location)
	   (setf (mob-location mob)location)
	   (push mob (location-contents location)))

(defun directions-mob-can-go (mob)
	   (mapcar #'car (mob-can-go mob)))

(put-mob david room1)

(defvar north 'north)
(defvar south 'south)
(defvar east  'east)
(defvar west  'west)

(defun get-destination (mob direction)
	   (second (assoc direction (mob-can-go mob))))

(defun move-mob (mob direction)
	   (if (find direction (directions-mob-can-go mob))
	       (progn 
		 (put-mob mob (symbol-value(get-destination mob direction)))
		 (remove-mob mob))
	       (format t "alas, you cannot go that way")))
 
From: Pascal Bourguignon
Subject: Re: newbie structure problem
Date: 
Message-ID: <871wwy8hkp.fsf@thalassa.informatimago.com>
david <·····@earthlink.net> writes:

> On Thu, 16 Mar 2006 14:14:55 +0100, Pascal Bourguignon wrote:
>
>
>> 
>> As you can see, there's a little problem here. You need to use the
>> symbol as an indirect pointer to the destination room.
>> 
>> It would be better if you modeled the rooms independently from the
>> association:

> also, what is an indirect pointer as opposed
> to a direct pointer? 

A pointer to a pointer is an indirect pointer.

Well, in lisp we don't handle the pointers directly.  
What happens is that some values are implemented as references.

For example, a CONS cell, an ARRAY, a SYMBOL, etc, are stored on the
heap, and when such a value is bound to a variable, the variable holds
actually a pointer to the CONS cell, the ARRAY or the SYMBOL, etc.

(let ((a 'exemple))
   (let ((b a))
    ;; b and a point to the same symbol: EXEMPLE
    (eq b a))) --> T


Of course, the value slot of a symbol can hold another such reference:

(defvar *c*)
(setf (symbol-value '*c*) 'exemple)
(let ((a *c*))
   ;; a and *c* point to the same symbol: EXEMPLE
   (eq a *c*)) --> T



Note, when you bind a lexical variable, the symbol-value of that
symbol is not affected:

(let ((a 'exemple))
   (symbol-value 'a))

*** - SYMBOL-VALUE: A has no dynamic value


Now you store a symbol in a variable when you want the value stored in
this symbol value slot, you have to go thru two pointers to access
this value:


(defparameter *c* "Value")
(let ((a '*c*))
   (symbol-value a))

First, we go thru the pointer stored in the variable a to get hold of
the symbol *C*, then we go thru the pointer stored in the value slot
of *C* to get hold of the value "Value".  Two pointers --> indirect.


> if i understand you correctly, i think my whole program design
> was based on using symbols as indirect pointers. is this bad?
> why? i can see for myself that it gets a little complicated accessing
> the properties i want. 

Using symbols this way is not necessarily bad.  (They were invented to
be used this way after all).  Perhaps it's a little old-fashioned now
that we have more data type in lisp than at the origin.

The problems with using symbols as you do in your case are:

- you have to invent names.  This is hard, then you come with
  meaningless names such as room1, room2, etc.  Is this an hotel?

- as always when using symbol you have to consider the possible name
  collisions.  For example, there's a symbol named ROOM in COMMON-LISP.  
  Perhaps you would consider using a different package for the
  names of your locations?

- it makes it harder to generate the locations programmatically;
  instead of just creating the location objects, now you have to
  create symbols to name them (with gensym perhaps?), and to set the
  indirection.

- each symbol can be thought as a record of five fields;
     - name
     - value
     - function
     - package
     - plist

  Granted, implementations can sometimes optimize out these space
  requirements, but anyways, this is rather costly if you only use
  them as an indirect pointer.   And since we have already a structure
  object, if we needed to store some property, we'd add a field to the
  object, so there's little reason to use the symbol-plist or
  symbol-function.

- you don't have a back-pointer from the location objects to their name!

(let ((here (get-some-room)))
   (print (location-description here))
   (let ((cmd (get-command))
         (from-room))
     (cond ((and (magicianp *mob*)
                 (spellp cmd)
                 (match '(create magic tunnel from room (? from-room)) cmd))
              (add-exit from-room (get-some-direction) ????))
           ...)))

  What would you put in ???? ?
  You cannot put here because you need a symbol, not a location...



> it seemed natural to me to make exits a property of locations but
> i know nothing of program design. 

Depends.  

If you have a passage from the sword-smith's to the potions-mixer's,
can't you go from the poitions-mixer's to the sword-smith's?

All right, some passages can be one-way (traps, magic channels,
etc). But usually you can go thru a door or a passage both ways.


Anyways, as I showed you with my code, the exits are still an
attribute of the location objects.  Only you don't set them right
away.  You first create a group of locations, then you tell where each
exit lead to.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d? s++:++ a+ C+++ UL++++ P--- L+++ E+++ W++ N+++ o-- K- w--- 
O- M++ V PS PE++ Y++ PGP t+ 5+ X++ R !tv b+++ DI++++ D++ 
G e+++ h+ r-- z? 
------END GEEK CODE BLOCK------