From: Alan Crowe
Subject: Does my macro create C style pointers?
Date: 
Message-ID: <86d60fbawf.fsf@cawtech.freeserve.co.uk>
In C you can pass the address of a variable to a function,
allowing the function to update the value of the variable.

CL's lexical variables don't permit this. If you are "old
school" then you make free use of dynamic scope and might
pass a symbol where C code would pass an address. For
example:

(defun inc-func(symbol)
  (incf (symbol-value symbol))

lets you write

(let ((x 100))
  (declare (special x))
  (inc-func 'x)
  x)            => 101

However, the semantics are not quite the same. The variable
can be captured by a special binding of the same symbol
along the call path.  I've created two intermediate
functions to illustrate the point

(defun intermediate1 (symbol)
  (let ((x -1)) ;lexical
    (inc-func symbol)
    (format t "~&First intermediate x: ~A" x)))

(defun intermediate2 (symbol)
  (let ((x -1))
    (declare (special x))
    (inc-func symbol)
    (format t "~&Second intermediate x: ~A" x)))

(let ((x 100))
  (declare (special x))
  (intermediate1 (quote x))
  (format t "~&First value of outer x: ~A" x)
  (intermediate2 (quote x))
  (format t "~&Second value of outer x: ~A" x)) 
=> 
     First intermediate x: -1
     First value of outer x: 101
     Second intermediate x: 0
     Second value of outer x: 101

Whoops, the second intermediate function grabbed the symbol x, and
got its x incremented leaving the outer x unchanged. Sometimes that is
exactly what you want

(let ((*readtable* *readtable*))
  (mess-with-readtable) ...

is a good way of making sure that the changes are undone at the end of 
the let form. But what if you want

(pointer (x 100)
  (intermediate1 &x)
  (format t "~&First value of outer x: ~A" x)
  (intermediate2 &x)
  (format t "~&Second value of outer x: ~A" x))
=> 
     First intermediate x: -1
     First value of outer x: 101
     Second intermediate x: -1
     Second value of outer x: 102

without any risk of variable capture

(defmacro pointer ((name initial-value) &body code)
  (let ((hidden-symbol (gensym))
	(addr-name (intern (format nil "&~A" name))))
    `(let ((,addr-name (quote ,hidden-symbol)))
       (symbol-macrolet ((,name ,hidden-symbol))
	 (let ((,hidden-symbol ,initial-value))
	   (declare (special ,hidden-symbol))
	   ,@code)))))

seems to do the trick.

Have I created an exact equivalent to the C idiom of taking
the address of a variable? As far as I can see tonight, I
have suceeded all too well, even reproducing the dynamic
extent of such an address.

Baron Alan Frankenstein
Edinburgh Castle
Scotland

From: Chris Capel
Subject: Re: Does my macro create C style pointers?
Date: 
Message-ID: <10l1pqhqpcga78c@corp.supernews.com>
Alan Crowe wrote:

> (defmacro pointer ((name initial-value) &body code)
>   (let ((hidden-symbol (gensym))
> (addr-name (intern (format nil "&~A" name))))
>     `(let ((,addr-name (quote ,hidden-symbol)))
>        (symbol-macrolet ((,name ,hidden-symbol))
> (let ((,hidden-symbol ,initial-value))
> (declare (special ,hidden-symbol))
> ,@code)))))
> 
(snip)
> 
> Have I created an exact equivalent to the C idiom of taking
> the address of a variable? As far as I can see tonight, I
> have suceeded all too well, even reproducing the dynamic
> extent of such an address.
> 

If this works like it looks like it works, then all I can say is

Super-Cool!

I could use this for my forthcoming collection libraries. Hehe.

Chris Capel
From: Pascal Bourguignon
Subject: Re: Does my macro create C style pointers?
Date: 
Message-ID: <87wtynfew0.fsf@thalassa.informatimago.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> In C you can pass the address of a variable to a function,
> allowing the function to update the value of the variable.
> [...]
> Have I created an exact equivalent to the C idiom of taking
> the address of a variable? As far as I can see tonight, I
> have suceeded all too well, even reproducing the dynamic
> extent of such an address.

I think it would be really hairy to try to implement ("emulate")
taking the address of a variable.

But it's quite easy to implement "pointers", actually references.

(defun pointer  (&optional object)  (cons :pointer object))
(defun pointerp (object)   (and (consp object) (eq (car object) :pointer)))
(defmacro deref (pointer) `(cdr ,pointer))


(let ((a (pointer 1))
      (b (pointer))
      (c)
      (h))
    (setf (deref b) (deref a))
    (setf h (pointer b))
    (setf (deref (deref h)) 2)
    (assert (= 2 (deref b)))
    (assert (= 1 (deref a)))
    (setf c a)
    (setf (deref c) 3)
    (assert (= 3 (deref a))))


You cannot make a pointer to some part of an existing value, but you
can encapsulate a whole value into a "pointer", and use it to later
change the value:

(defun strcpy (dst src) (setf  (deref dst) (copy-seq (deref src))))

(let ((a (pointer "Hello World"))
      (b (pointer "howdy")))
    (strcpy b a)
    (princ (deref b)))

Hello World
--> "Hello World"


I guess it would be possible to take  pointer to a value part with a
smart macro that would work somewhat like defsetf:

(defstruct person name age)

(deref (pointer (aref (person-name owner) 0))
would give an object containing two closures:
    (lambda ()  (aref (person-name owner) 0)) ; getter
    (lambda (x) (setf (aref (person-name owner) 0) x)) ; setter
and depending on its use as l-value or r-value, would use one or the other
(I guess thru the use of defsetf).


Perhaps you could check the sources of Zeta-C to see how they
implemented C pointers onto Lisp.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
From: Lars Brinkhoff
Subject: Re: Does my macro create C style pointers?
Date: 
Message-ID: <85r7oukd1i.fsf@junk.nocrew.org>
See also "locatives".

Here's a simple implementation of locatives for CL:
http://www.hexapodia.net/pipermail/small-cl-src/2004-June/000016.html

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/
From: Alan Crowe
Subject: Re: Does my macro create C style pointers?
Date: 
Message-ID: <86isa3jnge.fsf@cawtech.freeserve.co.uk>
Lars Brinkhoff wrote:
> Here's a simple implementation of locatives for CL:
> http://www.hexapodia.net/pipermail/small-cl-src/2004-June/000016.html

That you Lars, that is fascinating and difficult code.

I have studied it and placed my exegesis at

http://alan.crowe.name/lisp/locative.txt

It is probably of most interest to those who find
get-setf-expansion difficult and would be reassured to see
some-one else having to work hard to understand code that
uses it.

Alan Crowe
Edinburgh
Scotland
From: Rahul Jain
Subject: Re: Does my macro create C style pointers?
Date: 
Message-ID: <87pt48x1dq.fsf@nyct.net>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> Lars Brinkhoff wrote:
>> Here's a simple implementation of locatives for CL:
>> http://www.hexapodia.net/pipermail/small-cl-src/2004-June/000016.html
>
> That you Lars, that is fascinating and difficult code.
>
> I have studied it and placed my exegesis at
>
> http://alan.crowe.name/lisp/locative.txt
>
> It is probably of most interest to those who find
> get-setf-expansion difficult and would be reassured to see
> some-one else having to work hard to understand code that
> uses it.

Nice writeup! Now I don't need to answer the followup questions to my
response. ;)

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Alan Crowe
Subject: Re: Does my macro create C style pointers? (correction)
Date: 
Message-ID: <86llezjotz.fsf@cawtech.freeserve.co.uk>
I cannot believe I wrote 

     (let ((*readtable* *readtable*))
       (mess-with-readtable) ...

that doesn't work at all. In the past I've wasted hours,
utterly confused, until I learned about COPY-READTABLE.
The technique is sound in principle

(let ((*print-escape* *print-escape*))
    (write "The default")(terpri)
    (setf *print-escape* t)
    (write "Escaped")(terpri)
    (setf *print-escape* nil) ;I set *print-escape* to NIL
    (write "Un-escaped")(terpri))
"The default"
"Escaped"
Un-escaped
NIL
* *print-escape*
T <--- look the outer print escape is unharmed.

but it doesn't work for *readtable* and *random-state*
because they are structures. Without an explicit copy there
is only one structure, shared by both bindings of the
variable. Changes made via the inner binding are changes to
the single, shared, *readtable* and persist after the end of
the inner scope.

I got horribly confused by this when I started learning CL
(from a C background) so I cannot leave the mistake lying
there, ready to inflict similar misery on other newbies.

Alan Crowe
Edinburgh
Scotland
From: Rahul Jain
Subject: Re: Does my macro create C style pointers?
Date: 
Message-ID: <87u0tkx1k2.fsf@nyct.net>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> Have I created an exact equivalent to the C idiom of taking
> the address of a variable? As far as I can see tonight, I
> have suceeded all too well, even reproducing the dynamic
> extent of such an address.

Simply use get-setf-expansion. If you can't, then use
define-setf-expander first. ;)

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist