From: David Steuber
Subject: sb-thread programming tutorial?
Date: 
Message-ID: <87n04w7fpv.fsf@david-steuber.com>
I've glanced through the SBCL manual for things outside the ANSI
spec.  For instance, I am interested in threaded programming using
sb-thread.  While I am sure that apropos and describe are good for
reference purposes (or at least brief reminders), I am looking for a
gentler introduction to threaded programming with SBCL's sb-thread.

I've done simple threaded programming with the Win32 API and Java, but
that was a while back.  I know in general about things like
synchronization/serialization, race hazards, and deadlocks.  What I
don't know is how these are handled with sb-thread.

To quote a line from the SBCL manual:

"Dynamic bindings to symbols are per-thread. Signal handlers are
per-thread."

Although I have not seen how Lisp does signal handling, it is nice to
know that the handler will be called in the same thread that the
signal was raised.  That at least means that you can pretend the
thread is its own little world.  I'm not quite sure about the dynamic
bindings.  My interpretation is that

(defvar *foo* "bar")

means that every thread has *foo* with the initial value of "bar".  If
a thread does

(setf *foo* "baz")

then /that/ thread and /only/ that thread has *foo* bound to "baz".
If this is the case, then that is great.  I have a sort of thread
local storage thing going on for free.

That then leads me to wonder how to create a shareable object such as
a hash table (or an a-list) that has serialized access from all the
threads that need to touch it in some way.

Then there are other threading issues like waiting on objects (Java
style) and other scheduling issues.  For example, if thread creation
has too much overhead for a given purpose, I would want to pre-spawn a
number of threads and have them sleeping in a queue to be woken up as
needed to handle a request and then go back into the queue when
finished rather than exiting.

I still consider myself very much a Lisp beginner (neolisper?).  I
kind of skipped through macros and clos in Graham's ACL book.  I
figured I could come back to that stuff.  I am hoping that I have
enough ground work to handle seperate concepts such as threads and
also sockets and other things.

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.

From: Thomas F. Burdick
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <xcvvfjk37bc.fsf@famine.OCF.Berkeley.EDU>
David Steuber <·····@david-steuber.com> writes:

> To quote a line from the SBCL manual:
> 
> "Dynamic bindings to symbols are per-thread. Signal handlers are
> per-thread."
> 
> Although I have not seen how Lisp does signal handling, it is nice to
> know that the handler will be called in the same thread that the
> signal was raised.  That at least means that you can pretend the
> thread is its own little world.  I'm not quite sure about the dynamic
> bindings.  My interpretation is that
> 
> (defvar *foo* "bar")
> 
> means that every thread has *foo* with the initial value of "bar".  If
> a thread does
> 
> (setf *foo* "baz")
> 
> then /that/ thread and /only/ that thread has *foo* bound to "baz".
> If this is the case, then that is great.  I have a sort of thread
> local storage thing going on for free.

No no no!  What you're doing with SETF is, as its name implies,
setting the variable.  Binding is different, it creates a new variable
(name->value mapping).  LET and LAMBDA bind variables.  You do get
thread-local storage, but with dynamic binding; so:

  (defvar *foo* "global")

  (let ((*foo* "thread-local"))
    ...)

In the body of the LET, and all the code paths called from there,
*FOO* has the value "thread-local".  Not only that, but LET creates a
new binding, so any setting of *FOO* affects that binding, not the
global one.  No matter what, that dynamic contour cannot affect the
global value.  If *FOO* isn't bound, you access its global binding,
which would be shared by all threads.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: David Steuber
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <873c6n93w2.fsf@david-steuber.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> No no no!  What you're doing with SETF is, as its name implies,

I keep getting binding and setting mixed up.  I'll get it after enough
hammering on my skull.

> setting the variable.  Binding is different, it creates a new variable
> (name->value mapping).  LET and LAMBDA bind variables.  You do get
> thread-local storage, but with dynamic binding; so:
> 
>   (defvar *foo* "global")
> 
>   (let ((*foo* "thread-local"))
>     ...)
> 
> In the body of the LET, and all the code paths called from there,
> *FOO* has the value "thread-local".  Not only that, but LET creates a
> new binding, so any setting of *FOO* affects that binding, not the
> global one.  No matter what, that dynamic contour cannot affect the
> global value.  If *FOO* isn't bound, you access its global binding,
> which would be shared by all threads.

Ok, so (defvar *foo* "global") is shared and access needs to be
protected with a mutex.  Or is CL clever enough to provide mutexed
access for me?

How about this example (from Graham as best I can recall it):

(let ((count 0))
  (defun stamp () (1+ count))
  (defun reset () (setf count 0)))

Each thread should have its own copy of count for the purposes of
calling stamp and reset, correct?  Or are things not so simple?

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Thomas F. Burdick
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <xcvn04v380f.fsf@famine.OCF.Berkeley.EDU>
David Steuber <·····@david-steuber.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > No no no!  What you're doing with SETF is, as its name implies,
> 
> I keep getting binding and setting mixed up.  I'll get it after enough
> hammering on my skull.

What should eventually click is that binding creates new variables,
and setting gives new values to existing variables.  A variable is
just a mapping from a name to a value.

Where it gets a little more complex is there are two types of
variables: lexical variables, and dynmaic variables.  Lexical
variables (ie, the mapping from a name to a place to store/retrieve
values) exist only at compile time.  Dynamic variables exist at
runtime.

> Ok, so (defvar *foo* "global") is shared and access needs to be
> protected with a mutex.  Or is CL clever enough to provide mutexed
> access for me?

Nope, you gotta do it yourself.

> How about this example (from Graham as best I can recall it):
> 
> (let ((count 0))
>   (defun stamp ()
                    (incf count))
>   (defun reset () (setf count 0)))
> 
> Each thread should have its own copy of count for the purposes of
> calling stamp and reset, correct?  Or are things not so simple?

Things are quite simple here, but that's a lexical variable named
count.  So, it's resolved by the compiler, into a single place at
compile time.  For thread-local variables, you want to create a
binding at runtime, sometime after the spawning of the thread.  That's
exactly what dynamic binding does.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Fred Gilham
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <u7brlbpner.fsf@snapdragon.csl.sri.com>
David Steuber <·····@david-steuber.com> writes:


> How about this example (from Graham as best I can recall it):
> 
> (let ((count 0))
>   (defun stamp () (1+ count))
>   (defun reset () (setf count 0)))
> 
> Each thread should have its own copy of count for the purposes of
> calling stamp and reset, correct?  Or are things not so simple?


No.  The values of lexical variables are always obtained from the
lexically apparent bindings.  That's why they're called lexical
variables.

Note that the code above probably didn't do what you meant it to do;
you want

(let ((count 0))
  (defun stamp () (incf count))  ;;  <<<<----
  (defun reset () (setf count 0)))

instead.

It might help to think as follows.

A dynamic variable obeys a stack protocol; it gets its binding by
looking up the call stack to find a stack frame where it is bound.
But since threads can be considered to have cloned stacks, they each
have their own copy of the binding (or memory location) of the dynamic
variable.

A lexical variable, on the other hand, obeys a "lexical protocol",
which means that you can find the applicable binding for the variable
by looking at the enclosing binding forms.  The innermost binding form
that binds the variable in question is the one that creates the
binding for that variable, regardless of the call stack.  You can even
think of it as creating a pointer to a memory location, and
hard-coding the pointer into the code that references the variable.

So in the above example, you can think of a pointer to the memory
location 1234 which holds the value of count.  So both STAMP and RESET
have the number 1234, the address where the value of count is stored,
hard-coded into them so they will always reference that same memory
location.

This isn't exactly what really happens, but like I said, you can think
of it that way.

Here's some test code that runs under CMUCL that will illustrate what
is going on with closures and threads:

(let ((count 0))
  (defun stamp () (incf count))
  (defun reset () (setf count 0)))


(defun stamp-and-print (pid time)
  (loop
   (format t "Pid ~A: Count is ~A~%" pid (stamp))
   (sleep time)))

(defun reset-it ()
    (loop
     (reset)
     (sleep 10)))


(defun test-it ()
  (mp:make-process #'(lambda () (stamp-and-print 1 (random 2))))
  (mp:make-process #'(lambda () (stamp-and-print 2 (random 5))))
  (mp:make-process #'reset-it))


If you run (test-it) you'll get something like the following:

Pid 2: Count is 1
Pid 1: Count is 2
Pid 1: Count is 3
Pid 1: Count is 4
Pid 1: Count is 5
Pid 2: Count is 6
Pid 1: Count is 7
Pid 1: Count is 8
Pid 1: Count is 9
Pid 1: Count is 10
Pid 2: Count is 11
Pid 1: Count is 12
Pid 1: Count is 13
Pid 1: Count is 1
Pid 1: Count is 2
Pid 2: Count is 3
Pid 1: Count is 4
Pid 1: Count is 5
Pid 1: Count is 6
Pid 1: Count is 7
Pid 2: Count is 8
Pid 1: Count is 9
Pid 1: Count is 10
Pid 1: Count is 11
Pid 1: Count is 12
Pid 2: Count is 1
Pid 1: Count is 2
Pid 1: Count is 3
Pid 1: Count is 4
Pid 1: Count is 5
Pid 2: Count is 6
Pid 1: Count is 7
Pid 1: Count is 8
Pid 1: Count is 9
Pid 1: Count is 10
Pid 2: Count is 11
Pid 1: Count is 12
Pid 1: Count is 13
Pid 1: Count is 1

etc.


-- 
Fred Gilham                                 ······@csl.sri.com
[My tutors] got bored sooner than I, and laid down a general rule
that all statements about languages had to be in a higher level
language.  I thereupon asked in what level of language that rule was
formulated.  I got a very bad report.    -- J. R. Lucas
From: Fred Gilham
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <u74qr3pljf.fsf@snapdragon.csl.sri.com>
As another example, here's the special variable version with of the
previous example with thread-local bindings.  Notice that there seem
to be three separate instances of the *count* variable --- the
instance that (reset) accesses doesn't show up anywhere, but the point
is that the reset-it process has no effect on the other two processes.


(defvar *count* 0)

(defun stamp () (incf *count*))
(defun reset () (setf *count* 0))


(defun stamp-and-print (pid time)
  (loop
   (format t "Pid ~A: Count is ~A~%" pid (stamp))
   (sleep time)))

(defun reset-it ()
    (loop
     (reset)
     (sleep 10)))


(defun test-it ()
  (mp:make-process #'(lambda () (stamp-and-print 1 2)) :initial-bindings '((*count* .  0)))
  (mp:make-process #'(lambda () (stamp-and-print 2 5)) :initial-bindings '((*count* .  0)))
  (mp:make-process #'reset-it))


Here's the run:


Pid 2: Count is 1
Pid 1: Count is 1
Pid 1: Count is 2
Pid 1: Count is 3
Pid 2: Count is 2
Pid 1: Count is 4
Pid 1: Count is 5
Pid 2: Count is 3
Pid 1: Count is 6
Pid 1: Count is 7
Pid 1: Count is 8
Pid 2: Count is 4
Pid 1: Count is 9
Pid 1: Count is 10
Pid 2: Count is 5
Pid 1: Count is 11
Pid 1: Count is 12
Pid 1: Count is 13
Pid 2: Count is 6
Pid 1: Count is 14
Pid 1: Count is 15
Pid 2: Count is 7
Pid 1: Count is 16
Pid 1: Count is 17
Pid 1: Count is 18
Pid 2: Count is 8
Pid 1: Count is 19
Pid 1: Count is 20
Pid 2: Count is 9
Pid 1: Count is 21
Pid 1: Count is 22
Pid 1: Count is 23
Pid 2: Count is 10
Pid 1: Count is 24
Pid 1: Count is 25
Pid 2: Count is 11
Pid 1: Count is 26
Pid 1: Count is 27
Pid 1: Count is 28
Pid 2: Count is 12
Pid 1: Count is 29
Pid 1: Count is 30
Pid 2: Count is 13
Pid 1: Count is 31
Pid 1: Count is 32
Pid 1: Count is 33
Pid 2: Count is 14
Pid 1: Count is 34
Pid 1: Count is 35
Pid 2: Count is 15
Pid 1: Count is 36
Pid 1: Count is 37
Pid 1: Count is 38
Pid 2: Count is 16
Pid 1: Count is 39


-- 
Fred Gilham                                        ······@csl.sri.com
...the War between the States established...this principle, that the
federal government is, through its courts, the final judge of its own
powers.  -- Woodrow Wilson, explaining who will watch the watchers.
From: Arthur Lemmens
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <opr67jyurzk6vmsw@news.xs4all.nl>
Fred Gilham <······@snapdragon.csl.sri.com> wrote:

> A dynamic variable obeys a stack protocol; it gets its binding by
> looking up the call stack to find a stack frame where it is bound.
> But since threads can be considered to have cloned stacks, they each
> have their own copy of the binding (or memory location) of the dynamic
> variable.
>
> A lexical variable, on the other hand, obeys a "lexical protocol",
> which means that you can find the applicable binding for the variable
> by looking at the enclosing binding forms.  The innermost binding form
> that binds the variable in question is the one that creates the
> binding for that variable, regardless of the call stack.

One way of looking at this is that the binding of a dynamic variable
is determined by the run-time stack, whereas the binding of a lexical
variable is determined by the compile-time stack.

--
Arthur
From: David Steuber
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <87vfjj4p57.fsf@david-steuber.com>
David Steuber <·····@david-steuber.com> writes:

> (let ((count 0))
>   (defun stamp () (1+ count))
>   (defun reset () (setf count 0)))

Actually, I think that should be (defun stamp () (incf count)).

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Gabor Melis
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <fb0fb805.0404280224.500f4cf8@posting.google.com>
David Steuber <·····@david-steuber.com> wrote in message news:<··············@david-steuber.com>...
> I've glanced through the SBCL manual for things outside the ANSI
> spec.  For instance, I am interested in threaded programming using
> sb-thread.  While I am sure that apropos and describe are good for
> reference purposes (or at least brief reminders), I am looking for a
> gentler introduction to threaded programming with SBCL's sb-thread.
> 
> I've done simple threaded programming with the Win32 API and Java, but
> that was a while back.  I know in general about things like
> synchronization/serialization, race hazards, and deadlocks.  What I
> don't know is how these are handled with sb-thread.
> 
> To quote a line from the SBCL manual:
> 
> "Dynamic bindings to symbols are per-thread. Signal handlers are
> per-thread."
> 
> Although I have not seen how Lisp does signal handling, it is nice to
> know that the handler will be called in the same thread that the
> signal was raised.  That at least means that you can pretend the
> thread is its own little world.  I'm not quite sure about the dynamic
> bindings.  My interpretation is that
> 
> (defvar *foo* "bar")
> 
> means that every thread has *foo* with the initial value of "bar".  If
> a thread does
> 
> (setf *foo* "baz")
> 
> then /that/ thread and /only/ that thread has *foo* bound to "baz".
> If this is the case, then that is great.  I have a sort of thread
> local storage thing going on for free.

My impression was that (setf *foo* "baz") modifies the global binding
of *foo*  and since the global binding is shared by threads it is
suitable for inter-thread communication. However, if *foo* is rebound
with let in a thread then that binding is local to that particular
thread. Is that right?

Gabor
From: Tim Bradshaw
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <fbc0f5d1.0404280536.63adb87d@posting.google.com>
David Steuber <·····@david-steuber.com> wrote in message news:<··············@david-steuber.com>...
 that
> 
> (defvar *foo* "bar")
> 
> means that every thread has *foo* with the initial value of "bar".  If
> a thread does
> 
> (setf *foo* "baz")
> 

That's unlikely to be the case.  What *is* likely to be the case is
that if you *bind* a special in a thread, then that binding is
per-thread.  If you don't bind it, then the above assignment will
probably alter the global binding, or the parent thread's binding, or
something like that.

Some threading implementations (Allegro? I'm not sure) also have a set
of default special bindings which are established on thread creation,
which you might be able to add to.

--tim
From: Duane Rettig
Subject: Re: sb-thread programming tutorial?
Date: 
Message-ID: <4d65scdci.fsf@franz.com>
··········@tfeb.org (Tim Bradshaw) writes:

> David Steuber <·····@david-steuber.com> wrote in message news:<··············@david-steuber.com>...
>  that
> > 
> > (defvar *foo* "bar")
> > 
> > means that every thread has *foo* with the initial value of "bar".  If
> > a thread does
> > 
> > (setf *foo* "baz")
> > 
> 
> That's unlikely to be the case.  What *is* likely to be the case is
> that if you *bind* a special in a thread, then that binding is
> per-thread.  If you don't bind it, then the above assignment will
> probably alter the global binding, or the parent thread's binding, or
> something like that.
> 
> Some threading implementations (Allegro? I'm not sure) also have a set
> of default special bindings which are established on thread creation,
> which you might be able to add to.

Yes.  See

http://www.franz.com/support/documentation/6.2/doc/pages/variables/excl/s_cl-default-special-bindings_s.htm


-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Nikodemus Siivola
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <Pine.OSF.4.58.0404281241180.31988@kosh.hut.fi>
On Wed, 28 Apr 2004, David Steuber wrote:

> To quote a line from the SBCL manual:
>
> "Dynamic bindings to symbols are per-thread. Signal handlers are
> per-thread."

...

> (setf *foo* "baz")
>
> then /that/ thread and /only/ that thread has *foo* bound to "baz".

No. That's assignment, not binding.

What it means is that after you have done

 (let ((*foo* ...))
   ...)

then within that dynamic contour you can assign to *foo* without other
threads being affected.

If *foo* hasn't been bound (by LET) in the thread, then the assignments
affects all threads that haven't rebound their *foo*'s.

Cheers,

 -- Nikodemus
From: David Steuber
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <87brlb94uq.fsf@david-steuber.com>
Nikodemus Siivola <········@kosh.hut.fi> writes:

> On Wed, 28 Apr 2004, David Steuber wrote:
> 
> > To quote a line from the SBCL manual:
> >
> > "Dynamic bindings to symbols are per-thread. Signal handlers are
> > per-thread."
> 
> ...
> 
> > (setf *foo* "baz")
> >
> > then /that/ thread and /only/ that thread has *foo* bound to "baz".
> 
> No. That's assignment, not binding.
> 
> What it means is that after you have done
> 
>  (let ((*foo* ...))
>    ...)
> 
> then within that dynamic contour you can assign to *foo* without other
> threads being affected.
> 
> If *foo* hasn't been bound (by LET) in the thread, then the assignments
> affects all threads that haven't rebound their *foo*'s.

I see.  Thanks for the clarification.  Just to be sure that I have it,
dynamic bindings are the same as lexical bindings?  I am soooo used to
C terminology for variables (global, automatic, etc).

So if I've created (defvar *a-hash-table* (make-hashtable)) as a
top-level form, then for threads to safely access this, I need to have
a mutex for *a-hash-table* and make sure that each thread uses that
mutex.  Or do CL types get magical mutexes as well?

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Thomas Schilling
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <c6p8ln$eui9l$1@uni-berlin.de>
David Steuber wrote:

> I see.  Thanks for the clarification.  Just to be sure that I have it,
> dynamic bindings are the same as lexical bindings?

No!

* lexical variables can only be accessed within the form they are defined
but may live longer (e.g. via closures) -> limited scope, infinite extent

> (let ((x 1))
    (defun get-x () x)
    (defun inc-x () (incf x)))
INC-X
> x
Error: var X unbound
> (get-x)
1
> (inc-x)
2
> (inc-x)
3
...



* special vars can be accessed anywhere and can even be rebound temporarily
  -> indefinite scope, limited extend; see CLtL section 5.1.2

> (defvar *x* 1)
*X*
> (defun get-*x* () *x*)
GET-*X*
> (get-*x*)
1
> (progn
    (let ((*x* 3))
      (print (get-*x*)))
    (print (get-*x*))
3
1
NIL
> ...

it even works for func params:

(defun foo (&optional (*x* *x*)) ... )

this is equivalent to:

(defun foo (&optional x)
  (if x
    (let ((*x* x)) ... )
    ...))

or even

(defun foo (&optional x)
  (if x
    (let ((old-*x* *x*))
      (setf *x* x)
      ...
      (setf *x* old-*x*))))


so both are really nice features and have little in common with C-style
variable bindings.

- thomas (just another lisp newbe)

-- 
"But I don't expect to convince anyone (over 25) to go out and learn Lisp."
- Paul Graham.
Proved wrong. See c.l.l thread "Two unrelated remarks"
From: Nikodemus Siivola
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <Pine.OSF.4.58.0404290030460.368068@kosh.hut.fi>
On Wed, 28 Apr 2004, David Steuber wrote:

> dynamic bindings are the same as lexical bindings?  I am soooo used to
> C terminology for variables (global, automatic, etc).

Nonononononono.

Lexical bindings work in lexical scope. Dynamic bindings (aka special
bindings) work in dynamic scope. LET does both, depending on the type
of the variable: lexical variables are bound lexically, special
dynamically.

 (let ((x 0))
   ;; x is lexically bound here, and outside this
   ;; lexical block it doesn't exist -- unless there is another
   ;; binding, of course
   )

 (defvar *x* 1) ; defvar and defparameter make special variables

 (defun foo () (print *x*)) ; since *x* is special, it's value depends
                            ; on the call site

 (let ((*x* 2))
    (foo)          ; => 2
    (let ((*x* 3))
      (foo)        ; => 3
      (setf *x* 4)
      (foo))       ; => 4
    ;; here the previous binding has vanished, and we have...
    (foo))         ; => 2

 ;;; and once again the binding disappears, leaving
 (foo)             ; => 1

A good working model of dynamic binding by LET is to think of
(let ((*foo* (foo))) (frob)) as:

 (let ((old-val *foo*)
       (*foo* (foo)))
   (unwind-protect
      (frob)
    (setf *foo* old-val)))

For more info, try: <http://www.gigamonkeys.com/book/variables.html>

Cheers,

 -- Nikodemus
From: David Steuber
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <874qr363zz.fsf@david-steuber.com>
Nikodemus Siivola <········@kosh.hut.fi> writes:

> On Wed, 28 Apr 2004, David Steuber wrote:
> 
> > dynamic bindings are the same as lexical bindings?  I am soooo used to
> > C terminology for variables (global, automatic, etc).
> 
> Nonononononono.

Bad memories of an old piano teacher here.  Did I strike a chord?

> Lexical bindings work in lexical scope. Dynamic bindings (aka special
> bindings) work in dynamic scope. LET does both, depending on the type
> of the variable: lexical variables are bound lexically, special
> dynamically.
> 
>  (let ((x 0))
>    ;; x is lexically bound here, and outside this
>    ;; lexical block it doesn't exist -- unless there is another
>    ;; binding, of course
>    )
> 
>  (defvar *x* 1) ; defvar and defparameter make special variables

I sure hope that special == global.  Otherwise, I'm going to have some
serious brain hemorrhaging before I get this all sorted out.

>  (defun foo () (print *x*)) ; since *x* is special, it's value depends
>                             ; on the call site
> 
>  (let ((*x* 2))
>     (foo)          ; => 2
>     (let ((*x* 3))
>       (foo)        ; => 3
>       (setf *x* 4)
>       (foo))       ; => 4
>     ;; here the previous binding has vanished, and we have...
>     (foo))         ; => 2
> 
>  ;;; and once again the binding disappears, leaving
>  (foo)             ; => 1

Ok, I think this all makes sense.  It looks a lot like C++ scoping.
That is, the lexical binding hides the special binding.  I suppose the
(declaim (special *x*)) is kinda sorta like C++'s :: scope resolution
operator to get at the outside name?

> A good working model of dynamic binding by LET is to think of
> (let ((*foo* (foo))) (frob)) as:
> 
>  (let ((old-val *foo*)
>        (*foo* (foo)))
>    (unwind-protect
>       (frob)
>     (setf *foo* old-val)))

I was afraid there was a real frob.  CLHS has fround though.

> For more info, try: <http://www.gigamonkeys.com/book/variables.html>

I will.  Thanks.

Has anyone ever pointed out that C and Lisp are different?  I don't
mean like apples are different from oranges.  More like apples are
different from automobiles.  I really do think that knowledge of C
gets in the way of learning Lisp.  At least that seems to be my case.

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Thomas F. Burdick
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <xcvk6zz37pj.fsf@famine.OCF.Berkeley.EDU>
David Steuber <·····@david-steuber.com> writes:

> Nikodemus Siivola <········@kosh.hut.fi> writes:
> 
> > On Wed, 28 Apr 2004, David Steuber wrote:
> > 
> > > dynamic bindings are the same as lexical bindings?  I am soooo used to
> > > C terminology for variables (global, automatic, etc).
> > 
> > Nonononononono.
> 
> Bad memories of an old piano teacher here.  Did I strike a chord?
> 
> > Lexical bindings work in lexical scope. Dynamic bindings (aka special
> > bindings) work in dynamic scope. LET does both, depending on the type
> > of the variable: lexical variables are bound lexically, special
> > dynamically.
> > 
> >  (let ((x 0))
> >    ;; x is lexically bound here, and outside this
> >    ;; lexical block it doesn't exist -- unless there is another
> >    ;; binding, of course
> >    )
> > 
> >  (defvar *x* 1) ; defvar and defparameter make special variables
> 
> I sure hope that special == global.  Otherwise, I'm going to have some
> serious brain hemorrhaging before I get this all sorted out.

Nope, sorry.  (eql special dynamic).  All globals are special, but not
all specials are global:

  * (defun foo ()
      (let ((x :lexical))
        (format t "X as a lexical has the following value: ~S~%" x)
        (locally (declare (special x))
          (format t "X as a special has the following value: ~S~%" x))))
  FOO
  * (let ((x :special))
      (declare (special x))
      (foo))
  X as a lexical has the following value: :LEXICAL
  X as a special has the following value: :SPECIAL
  NIL
  * (foo)
  X as a lexical has the following value: :LEXICAL
  
  Error in KERNEL::UNBOUND-SYMBOL-ERROR-HANDLER:  the variable X is unbound.

> Has anyone ever pointed out that C and Lisp are different?  I don't
> mean like apples are different from oranges.  More like apples are
> different from automobiles.

That's a good way of putting it.

> I really do think that knowledge of C gets in the way of learning
> Lisp.  At least that seems to be my case.

If you try to cast Lisp into C terms, it certainly will :-P

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Fred Gilham
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <u77jvzpm36.fsf@snapdragon.csl.sri.com>
> Ok, I think this all makes sense.  It looks a lot like C++ scoping.
> That is, the lexical binding hides the special binding.  

No, this is not the case.  Once a variable is declared special,
anything that binds it will bind it in the dynamic environment (aka
the call stack).  There won't be any lexical binding.  Any function in
the call chain can create a binding for the variable in its stack
frame.

> I suppose the (declaim (special *x*)) is kinda sorta like C++'s ::
> scope resolution operator to get at the outside name?

No.  Well, I suppose you could say yes, because both have something to
do with scope, but I guess it's like transistors and hydrogen bombs
are kinda sorta alike because they both work on the same
principle. :-)

In fact, when you declare a variable special, you still might look at
local bindings.  But those bindings are in the dynamic environment
instead of the lexical environment.

Don't confuse special variables with global variables.  You can have
local special declarations, and you can bind special variables
locally.  The big benefit of specials is that they automatically reset
themselves to their previous values (if any) when you exit the scope
of the current binding.  This lets you use them as implicit parameters
in a less error-prone way than if they were just global variables.
However, they are still somewhat error-prone because they are not
lexically obvious.  You might access a special variable without
realizing it if you happened to make a typo that referred to one.
That's why people advocate using the *special-variable* naming
convention.

-- 
Fred Gilham                                       ······@csl.sri.com
Early in our marriage, 40-some years ago, Mrs. Williams would return
from shopping complaining about the unreasonable prices.  Having aired
her complaints, she'd then ask me to unload her car laden with
purchases.  After the unloading, I'd ask her: "I thought you said the
prices were unreasonable.  Why did you buy them?  Are you
unreasonable?  Only an unreasonable person would pay unreasonable
prices."  The discussion always headed downhill after such an
observation.                             -- Walter Williams, economist
From: Nikodemus Siivola
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <Pine.OSF.4.58.0404291253430.112075@kosh.hut.fi>
On Wed, 28 Apr 2004, David Steuber wrote:

> I sure hope that special == global.  Otherwise, I'm going to have some
> serious brain hemorrhaging before I get this all sorted out.

All global variables are special variables, but not all special variables
are global -- at least in the usual sense of the word.

My suggestion would be to ignore the non-global special variables for now:
when you get global specials non-globals are a piece of cake, but may
create confusion en route.

> Ok, I think this all makes sense.  It looks a lot like C++ scoping.
> That is, the lexical binding hides the special binding.  I suppose the
> (declaim (special *x*)) is kinda sorta like C++'s :: scope resolution
> operator to get at the outside name?

I can't really comment on that, since my C++ skills suck almost as much as
the C++ language. ;)

However, I would suggest you to let sb-threads lie till you can understant
CL special variables and scoping mechanisms on their own terms: before
that you'll just make your learning more difficult by mixing threading in.

Cheers,

 -- Nikodemus
From: Tim Bradshaw
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <fbc0f5d1.0404290730.4766d759@posting.google.com>
Nikodemus Siivola <········@kosh.hut.fi> wrote in message news:<··································@kosh.hut.fi>...

> 
> All global variables are special variables, but not all special variables
> are global -- at least in the usual sense of the word.

Well, all system provided globals are specual, but it's not enormously
hard to define global lexicals (albeit by a trick).

> 
> My suggestion would be to ignore the non-global special variables for now:
> when you get global specials non-globals are a piece of cake, but may
> create confusion en route.

I'm not sure I agree, but I'm not sure I disagree either.  If you want
to bite the special variables bullet you might want to look at some of
the stuff at http://www.tfeb.org/lisp/ (shameless self-promotion,
sorry): in particular there are some notes there on specials as well
as examples of global lexicals (in toys.html) and local specials (in
hax.html).

--tim
From: Duane Rettig
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <43c6mdb5e.fsf@franz.com>
··········@tfeb.org (Tim Bradshaw) writes:

> the stuff at http://www.tfeb.org/lisp/ (shameless self-promotion,
> sorry):

First you say "shameless", then you say "sorry".  C'mon, Tim,
make up your mind - which one is it?

:-)

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: David Steuber
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <87isficsk2.fsf@david-steuber.com>
Duane Rettig <·····@franz.com> writes:

> ··········@tfeb.org (Tim Bradshaw) writes:
> 
> > the stuff at http://www.tfeb.org/lisp/ (shameless self-promotion,
> > sorry):
> 
> First you say "shameless", then you say "sorry".  C'mon, Tim,
> make up your mind - which one is it?

Since there is a Paul Graham quote there, I'd say it's product
placement and Tim just got a nickel.

I working on puting C concepts into a seperate namespace from Lisp
concepts:

namespace C;
...
namespace Lisp;

:-P

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Rahul Jain
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <8765bgf16t.fsf@nyct.net>
David Steuber <·····@david-steuber.com> writes:

> I working on puting C concepts into a seperate namespace from Lisp
> concepts:
>
> namespace C;
> ...
> namespace Lisp;

You mean (as the first step of that process)

namespace C;

(in-package :lisp)

;)

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: David Steuber
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <87oep78ujn.fsf@david-steuber.com>
Rahul Jain <·····@nyct.net> writes:

> David Steuber <·····@david-steuber.com> writes:
> 
> > I working on puting C concepts into a seperate namespace from Lisp
> > concepts:
> >
> > namespace C;
> > ...
> > namespace Lisp;
> 
> You mean (as the first step of that process)
> 
> namespace C;
> 
> (in-package :lisp)
> 
> ;)

Yes, that.

And along the way,

(with-lisp-jargon
  (assert (location 'brain 'in-skull)))

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Tim Bradshaw
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <fbc0f5d1.0405030651.ad4af52@posting.google.com>
Duane Rettig <·····@franz.com> wrote in message news:<·············@franz.com>...

> 
> First you say "shameless", then you say "sorry".  C'mon, Tim,
> make up your mind - which one is it?

I'm English: it's pretty much mandatory for me to be sorry for
everything.  After all, we're to blame for everything (well,
everything the Romans aren't to blame for).

--tim
From: Duane Rettig
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <4fzah8q4q.fsf@franz.com>
··········@tfeb.org (Tim Bradshaw) writes:

> Duane Rettig <·····@franz.com> wrote in message news:<·············@franz.com>...
> 
> > 
> > First you say "shameless", then you say "sorry".  C'mon, Tim,
> > make up your mind - which one is it?
> 
> I'm English: it's pretty much mandatory for me to be sorry for
> everything.  After all, we're to blame for everything (well,
> everything the Romans aren't to blame for).

OK, sorry.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Thomas Schilling
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <c75u4h$391o$1@uni-berlin.de>
Tim Bradshaw wrote:

> I'm English: it's pretty much mandatory for me to be sorry for
> everything.  After all, we're to blame for everything (well,
> everything the Romans aren't to blame for).

Oh! I thought this were the Germans? At least that's a common rumour
here ...  ;-)
From: Tim Bradshaw
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <ey365bdmic2.fsf@cley.com>
* Thomas Schilling wrote:
> Oh! I thought this were the Germans? At least that's a common rumour
> here ...  ;-)

Well, yes, except of course we're to blame for the Germans.

--tim
From: Marco Antoniotti
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <Srrmc.151$a5.46468@typhoon.nyu.edu>
Thomas Schilling wrote:

> Tim Bradshaw wrote:
> 
> 
>>I'm English: it's pretty much mandatory for me to be sorry for
>>everything.  After all, we're to blame for everything (well,
>>everything the Romans aren't to blame for).
> 
> 
> Oh! I thought this were the Germans? At least that's a common rumour
> here ...  ;-)

It's us the Italians.  We gave Fascism to the world in 1922 and 
Televisionism in 1994.

Cheers

--
Marco
From: Nikodemus Siivola
Subject: Re: [Sbcl-help] sb-thread programming tutorial?
Date: 
Message-ID: <Pine.OSF.4.58.0404291335560.112075@kosh.hut.fi>
On Wed, 28 Apr 2004, David Steuber wrote:

> Has anyone ever pointed out that C and Lisp are different?  I don't
> mean like apples are different from oranges.  More like apples are
> different from automobiles.  I really do think that knowledge of C
> gets in the way of learning Lisp.  At least that seems to be my case.

On a further thought, SICP might help here. It won't help you with
specials, packages or macros, and it has occasionally been accused of
causing scheme-braindamage in unsuspecting victims, but it should help
break C/C++ induced thought-patterns.

 <http://mitpress.mit.edu/sicp/>

Cheers,

 -- Nikodemus