From: Mariano Montone
Subject: gensym problem
Date: 
Message-ID: <a43c8813-ad2e-4c0c-ad36-a0ff0c9814ec@y38g2000hsy.googlegroups.com>
Hi,
      I'm using SBCL and have a problem with gensym.

      The symbols generated when I call macroexpand are different from
the ones when I evaluate the expression. When I call macroexpand
symbols work well, they have the form #:GXXX  (X is a number), all
different. But if I evaluate the expression I get "buggy" symbols with
the form: #:GX and "repeated"   (the problem is not their form, but
the "repetition")

      I know I'm not being clear. I'm just hoping someone will
identify this as a common problem. I'll try to be more clear if no one
answers.

Thanks, Mariano

From: Rainer Joswig
Subject: Re: gensym problem
Date: 
Message-ID: <joswig-A238FF.15580621052008@news-europe.giganews.com>
In article 
<····································@y38g2000hsy.googlegroups.com>,
 Mariano Montone <··············@gmail.com> wrote:

> Hi,
>       I'm using SBCL and have a problem with gensym.
> 
>       The symbols generated when I call macroexpand are different from
> the ones when I evaluate the expression. When I call macroexpand
> symbols work well, they have the form #:GXXX  (X is a number), all
> different. But if I evaluate the expression I get "buggy" symbols with
> the form: #:GX and "repeated"   (the problem is not their form, but
> the "repetition")
> 
>       I know I'm not being clear. I'm just hoping someone will
> identify this as a common problem. I'll try to be more clear if no one
> answers.
> 
> Thanks, Mariano

Posting example code and an example interaction would surely help.

-- 
http://lispm.dyndns.org/
From: Mariano Montone
Subject: Re: gensym problem
Date: 
Message-ID: <cdf9feaf-181c-419c-8469-fa0545508cfd@m36g2000hse.googlegroups.com>
On May 21, 10:58 am, Rainer Joswig <······@lisp.de> wrote:
> Posting example code and an example interaction would surely help.
>

Aha! My problem is with threads!

Code:

(defmacro gena ()
  (let ((s (gensym)))
    (format *standard-output* "Symbol generated: ~A~%" s)))

(defmacro genn (&rest body)
  `(progn
     ,@(loop for i from 1 to 5 collect
	    `(sb-thread:make-thread
	      (lambda ()
		,@body)))))


Expression: (genn (gena))

If I evaluate the expression I get:
CL-USER> (genn (gena))
Symbol generated: G0
Symbol generated: G0
Symbol generated: G0
Symbol generated: G0
Symbol generated: G0
#<SB-THREAD:THREAD {1003913F61}>


If I only macroexpand it:
Symbol generated: G2018
Symbol generated: G2027
Symbol generated: G2028
Symbol generated: G2029
Symbol generated: G2030
Symbol generated: G2031
Symbol generated: G2032
Symbol generated: G2033
Symbol generated: G2034
Symbol generated: G2035

which is closer to my desired behavior (I don't know why 10 symbols
are generated instead of 5 yet).

I don't know how to get the desired behavior, though. I'll try to
"remove" the threads. Looks like macroexpansion is occurring in the
threads, doesn't it?

Mariano
From: Thomas A. Russ
Subject: Re: gensym problem
Date: 
Message-ID: <ymik5hnbjgs.fsf@blackcat.isi.edu>
Mariano Montone <··············@gmail.com> writes:

> On May 21, 10:58 am, Rainer Joswig <······@lisp.de> wrote:
> > Posting example code and an example interaction would surely help.
> >
> 
> Aha! My problem is with threads!
> 
> Code:
> 
> (defmacro gena ()
>   (let ((s (gensym)))
>     (format *standard-output* "Symbol generated: ~A~%" s)))
> 
> (defmacro genn (&rest body)
>   `(progn
>      ,@(loop for i from 1 to 5 collect
> 	    `(sb-thread:make-thread
> 	      (lambda ()
> 		,@body)))))
> 
> 
> Expression: (genn (gena))
> 
> If I evaluate the expression I get:
> CL-USER> (genn (gena))
> Symbol generated: G0
> Symbol generated: G0
> Symbol generated: G0
> Symbol generated: G0
> Symbol generated: G0
> #<SB-THREAD:THREAD {1003913F61}>

Well, it shouldn't really matter that the gensyms have the same print
name, since they will be separate symbol objects, even with the same
name.  The only thing it makes harder is debugging, but you shouldn't
generally rely on gensym names to mean anything....

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Mariano Montone
Subject: Re: gensym problem
Date: 
Message-ID: <c9985aed-1d52-4884-a2a4-895f1120643e@d1g2000hsg.googlegroups.com>
On May 21, 3:28 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Well, it shouldn't really matter that the gensyms have the same print
> name, since they will be separate symbol objects, even with the same
> name.  The only thing it makes harder is debugging, but you shouldn't
> generally rely on gensym names to mean anything....

Aha, but I was using (string (gensym)) as entries of a hash table at
compile-time. :S

Now I need to think of a workaround taking into account that
macroexpansions can occur indefinite times. Or give up on macros and
look into code waking.

Mariano
From: Thomas F. Burdick
Subject: Re: gensym problem
Date: 
Message-ID: <6a3aaf21-5a0c-4b34-9f02-350c948c70ac@p39g2000prm.googlegroups.com>
On May 21, 9:40 pm, Mariano Montone <··············@gmail.com> wrote:
> On May 21, 3:28 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
>
> > Well, it shouldn't really matter that the gensyms have the same print
> > name, since they will be separate symbol objects, even with the same
> > name.  The only thing it makes harder is debugging, but you shouldn't
> > generally rely on gensym names to mean anything....
>
> Aha, but I was using (string (gensym)) as entries of a hash table at
> compile-time. :S
>
> Now I need to think of a workaround taking into account that
> macroexpansions can occur indefinite times. Or give up on macros and
> look into code waking.

You still don't tell us *what* you're doing, so I have the feeling
that I'm giving you noose-tying tips, but you could use the cons cell
of the &whole form.  Something like:

(defun with-bad-idea (&whole form (var &rest options) &body body)
  (setf (gethash *bad-ideas* form) (make-bad-idea options))
  `(let ((,var (get-bad-idea ',form)))
     ,@body))

But again, I have no idea if that's vaguely appropriate because you're
intentionally being coy about what you're doing.
From: Mariano Montone
Subject: Re: gensym problem
Date: 
Message-ID: <304b5181-ebdb-4183-aa91-ff799b3af1a6@r66g2000hsg.googlegroups.com>
On May 22, 4:58 am, "Thomas F. Burdick" <········@gmail.com> wrote:
> On May 21, 9:40 pm, Mariano Montone <··············@gmail.com> wrote:
>
> > On May 21, 3:28 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
>
> > > Well, it shouldn't really matter that the gensyms have the same print
> > > name, since they will be separate symbol objects, even with the same
> > > name.  The only thing it makes harder is debugging, but you shouldn't
> > > generally rely on gensym names to mean anything....
>
> > Aha, but I was using (string (gensym)) as entries of a hash table at
> > compile-time. :S
>
> > Now I need to think of a workaround taking into account that
> > macroexpansions can occur indefinite times. Or give up on macros and
> > look into code waking.
>
> You still don't tell us *what* you're doing, so I have the feeling
> that I'm giving you noose-tying tips, but you could use the cons cell
> of the &whole form.  Something like:
>
> (defun with-bad-idea (&whole form (var &rest options) &body body)
>   (setf (gethash *bad-ideas* form) (make-bad-idea options))
>   `(let ((,var (get-bad-idea ',form)))
>      ,@body))
>
> But again, I have no idea if that's vaguely appropriate because you're
> intentionally being coy about what you're doing.

I just didn't know how to express the problem without posting tons of
code.

My intention was to play with concurrent programming and conditional
regions.

So I defined a defprocess macro. It takes the name of the process and
the number of processes to fire:

(defmacro defprocess (name (&optional (var 'this) &key (from 1) (to
1)) &body body)
  (when (> from to) (error ":from cannot be greater thant :to"))
  (when (gethash name *processes*)
    (warn (format nil "A process named ~A has already been defined"
name)))
  `(progn
     ,@(loop for process from from to to
	  collect
	    `(setf (gethash ',name *processes*)
		   (sb-thread:make-thread
		    (lambda ()
		      (let ((,var ,process))
			(declare (ignorable ,var))
			,@body)))))
     nil))

To provide mutual exclusion and synchronization we use resources and
regions:

Example:

(defresource game
    (children 0))

(defvar *max-children* 2)

(defprocess boy (this :from 1 :to 5)
  (format *output* "Boy ~A: beginning.~%" this)
  (region game (:when (< children *max-children*))
    (incf children)
    (format *output* "Children playing game: ~A~%" children))
  (format *output* "Boy ~A: playing the game.~%" this)
  (delay 4)
  (region pasamanos ()
    (decf children))
  (format *output* "Boy ~A: exits the game.~%" this))

The problem is with region. region is a macro and I need to define
data for each one at compile time in a separate global space (a hash-
table)

So I thought of  hash-table indexed by gensyms (pay attention to the
uppercase):

(defmacro region (name (&key (when 't)) &body body)
  (with-semaphore *regions-mutex*
    (with-gensyms (lock resource) <--   THE GENSYM  (this would
provide a unique space for each compiled region in the global hash-
table at compile-time)
        (let*
	  ((res (if (gethash name *resources*)
		    (gethash name *resources*)
		    (error (format nil "Resource ~A not defined when trying to
compile region" name))))
	   (macrolet-slots (loop for slot in (resource-slot-names res)
			      collect `(,slot (resource-slot-value ,resource ',slot))))
	   (lock (string lock))   <-- MAKE THE GENSYM A STRING
	   (resource-regions-locks
	    (if (null (gethash (string name) *regions-locks*))
		(setf (gethash (string name) *regions-locks*) (make-hash-table :test
#'equal :synchronized t))
		(gethash (string name) *regions-locks*))))
	(setf (gethash lock resource-regions-locks) (sb-thread:make-
semaphore :name lock :count 0))     <-- HASH-TABLE POPULATION
	`(...)))))

But it doesn't work for several reasons. First, the gensyms being
generated are repeated in their string representation (I think it's
because of the threads of defprocess) and that means different regions
share the same space in the hash-table (what is incorrect). Second,
macroexpansion occurs several times and the hash-table gets populated
several times unnecessarily.

Hope my explanation wasn't very confusing.

Mariano
From: Thomas A. Russ
Subject: Re: gensym problem
Date: 
Message-ID: <ymimymidx6p.fsf@blackcat.isi.edu>
Mariano Montone <··············@gmail.com> writes:

> But it doesn't work for several reasons. First, the gensyms being
> generated are repeated in their string representation (I think it's
> because of the threads of defprocess) and that means different regions
> share the same space in the hash-table (what is incorrect). Second,
> macroexpansion occurs several times and the hash-table gets populated
> several times unnecessarily.

OK.  The crux of the problem is that you were relying on GENSYM to
generate a unique NAME for you, rather than generating a unique SYMBOL.
Now, internally, most gensym implementations utilize a special variable
which is the counter that gets incremented.

When you add processes into the mix, you often get process-local special
variables.  This is generally a Good Thing(tm) with multi-processing,
because otherwise you would have unpredictable interactions if different
threads were to change the values of these dynamic variables (such as,
for example, *print-base*).  So this also affect the internal counter
used by gensym.

I think the best solution is to use your own procedure for generating
unique names.  This can also be counter-based, but you need to make sure
that you are using a global counter, rather than one that is maintained
on a per-thread basis.  This is almost certainly possible, but you will
have to look at the SBCL documentation to find out how to do it.  You
will also have to synchronize access to the counter so that is really
will generate unique names for you.

The other advantage of this approach is that you have complete control
over the name generation, so you will be sure that it works the way you
want it to.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Mariano Montone
Subject: Re: gensym problem
Date: 
Message-ID: <0c437836-01f5-4aa9-b270-500013127293@59g2000hsb.googlegroups.com>
On May 22, 3:13 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Mariano Montone <··············@gmail.com> writes:
> > But it doesn't work for several reasons. First, the gensyms being
> > generated are repeated in their string representation (I think it's
> > because of the threads of defprocess) and that means different regions
> > share the same space in the hash-table (what is incorrect). Second,
> > macroexpansion occurs several times and the hash-table gets populated
> > several times unnecessarily.
>
> OK.  The crux of the problem is that you were relying on GENSYM to
> generate a unique NAME for you, rather than generating a unique SYMBOL.
> Now, internally, most gensym implementations utilize a special variable
> which is the counter that gets incremented.
>
> When you add processes into the mix, you often get process-local special
> variables.  This is generally a Good Thing(tm) with multi-processing,
> because otherwise you would have unpredictable interactions if different
> threads were to change the values of these dynamic variables (such as,
> for example, *print-base*).  So this also affect the internal counter
> used by gensym.
>
> I think the best solution is to use your own procedure for generating
> unique names.  This can also be counter-based, but you need to make sure
> that you are using a global counter, rather than one that is maintained
> on a per-thread basis.  This is almost certainly possible, but you will
> have to look at the SBCL documentation to find out how to do it.  You
> will also have to synchronize access to the counter so that is really
> will generate unique names for you.
>
> The other advantage of this approach is that you have complete control
> over the name generation, so you will be sure that it works the way you
> want it to.
>
> --
> Thomas A. Russ,  USC/Information Sciences Institute

Thanks. That solves the multi threading problem. Any suggestions on
how to get rid of the macroexpansion being evaluated several times?
Note that I cannot uniquely identify the regions by their arguments (I
cannot use its name nor its code (two different regions could work on
the same resource and have the same body))

Mariano
From: Thomas F. Burdick
Subject: Re: gensym problem
Date: 
Message-ID: <83104e43-ff7f-4d03-b9d4-600c8a967658@u6g2000prc.googlegroups.com>
On May 23, 3:22 am, Mariano Montone <··············@gmail.com> wrote:

> Thanks. That solves the multi threading problem. Any suggestions on
> how to get rid of the macroexpansion being evaluated several times?
> Note that I cannot uniquely identify the regions by their arguments (I
> cannot use its name nor its code (two different regions could work on
> the same resource and have the same body))

Can't you?  The name of the region plus the name of everything
enclosing it seems like it would be a unique identifier.  In your
example you could have a region named ((process boy) (region game))
for example.

The technique for passing macroexpansion-time information lexically
downwards is to hook on macroexpansion in a given environment.  Eg:

(define-symbol-macro %context-name ())

(defun environment-name (env) (macroexpand-1 '%context-name env))

(defmacro with-more-name (name-part &body body &environment env)
  (let ((name (append (environment-name env) name-part)))
    `(symbol-macrolet ((%context-name ,name))
       ,@body)))
From: Mariano Montone
Subject: Re: gensym problem
Date: 
Message-ID: <5b551f6a-cacd-4ea8-bda8-0a43ca5118eb@d77g2000hsb.googlegroups.com>
On May 23, 5:09 am, "Thomas F. Burdick" <········@gmail.com> wrote:
> On May 23, 3:22 am, Mariano Montone <··············@gmail.com> wrote:
>
> > Thanks. That solves the multi threading problem. Any suggestions on
> > how to get rid of the macroexpansion being evaluated several times?
> > Note that I cannot uniquely identify the regions by their arguments (I
> > cannot use its name nor its code (two different regions could work on
> > the same resource and have the same body))
>
> Can't you?  The name of the region plus the name of everything
> enclosing it seems like it would be a unique identifier.

I can't. The problem is "the name of the region" is not the name of
the region but the name of the shared resource processes are trying to
access. And I will probably access the same resource in the same
process several times :S

Anyway, I've learned a new trick from your code. So thanks!

Mariano
From: Pascal J. Bourguignon
Subject: Re: gensym problem
Date: 
Message-ID: <7cve17r908.fsf@pbourguignon.anevia.com>
Mariano Montone <··············@gmail.com> writes:

> On May 21, 10:58 am, Rainer Joswig <······@lisp.de> wrote:
>> Posting example code and an example interaction would surely help.
>>
>
> Aha! My problem is with threads!
>
> Code:
>
> (defmacro gena ()
>   (let ((s (gensym)))
>     (format *standard-output* "Symbol generated: ~A~%" s)))
>
> (defmacro genn (&rest body)
>   `(progn
>      ,@(loop for i from 1 to 5 collect
> 	    `(sb-thread:make-thread
> 	      (lambda ()
> 		,@body)))))
>
>
> Expression: (genn (gena))
>
> If I evaluate the expression I get:
> CL-USER> (genn (gena))
> Symbol generated: G0
> Symbol generated: G0
> Symbol generated: G0
> Symbol generated: G0
> Symbol generated: G0
> #<SB-THREAD:THREAD {1003913F61}>
>
>
> If I only macroexpand it:
> Symbol generated: G2018
> Symbol generated: G2027
> Symbol generated: G2028
> Symbol generated: G2029
> Symbol generated: G2030
> Symbol generated: G2031
> Symbol generated: G2032
> Symbol generated: G2033
> Symbol generated: G2034
> Symbol generated: G2035
>
> which is closer to my desired behavior (I don't know why 10 symbols
> are generated instead of 5 yet).
>
> I don't know how to get the desired behavior, though. I'll try to
> "remove" the threads. Looks like macroexpansion is occurring in the
> threads, doesn't it?

Macroexpansions can occur at anytime, and any number of times. You're
lucky to get only twice the five symbols, you could as well have
gotten fifty or 42.  

That's the reason why it's advised to avoid side effects in macros.


Why do you try to use macros?  There's absolutely no need to.

(defun gena ()
  (let ((s (gensym)))
    (format *standard-output* "Symbol generated: ~A~%" s)
    s))

(defun genn (fun)
  (loop
     :repeat 5
     :collect (sb-thread:make-thread fun)))

S/CL-USER[4]> (genn (function gena))
Symbol generated: G1857
Symbol generated: G1858
Symbol generated: G1859
Symbol generated: G1860
Symbol generated: G1861
(#<SB-THREAD:THREAD {1002C70A11}> #<SB-THREAD:THREAD {1002C70B81}> #<SB-THREAD:THREAD {1002C70CF1}> #<SB-THREAD:THREAD {1002C70E61}> #<SB-THREAD:THREAD {1002C70FD1}>)


-- 
__Pascal Bourguignon__
From: Mariano Montone
Subject: Re: gensym problem
Date: 
Message-ID: <237aa5ff-9f54-4da7-a7b2-cba1be85ffdb@l42g2000hsc.googlegroups.com>
On May 21, 12:07 pm, ····@informatimago.com (Pascal J. Bourguignon)
wrote:

> Macroexpansions can occur at anytime, and any number of times. You're
> lucky to get only twice the five symbols, you could as well have
> gotten fifty or 42.
>
> That's the reason why it's advised to avoid side effects in macros.

Good to know that!

>
> Why do you try to use macros?  There's absolutely no need to.

The code I posted is a representation of a more complex one where I do
need macros. I'll see if I can refactor it someway.

Thanks for your help,
                      Mariano