Does my macro create C style pointers?

From: Alan Crowe (alan_at_cawtech.freeserve.co.uk)
Date: 09/21/04


Date: 21 Sep 2004 21:54:40 +0100

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



Relevant Pages

  • Re: struct and typedef problems
    ... >> So u have to include the other file into this file and declare the ... >> structure in the other file with extern keyword. ... > Please provide some context when posting a followup. ... > quote the entire article, just enough to make it possible to ...
    (comp.lang.c)
  • Re: struct and typedef problems
    ... >> So u have to include the other file into this file and declare the ... >> structure in the other file with extern keyword. ... > Please provide some context when posting a followup. ... > quote the entire article, just enough to make it possible to ...
    (comp.lang.c)
  • Re: nullpointerexception
    ... JAI is not a package most people use. ... So how about you quote the ... javaDoc for create, and also post your code for the create call along ... with the code you use to declare the various parameters. ...
    (comp.lang.java.help)
  • Re: generating public int this[int index] {}
    ... it will declare an indexer property for the class. ... If replying to the group, please do not mail me too ...
    (microsoft.public.dotnet.languages.csharp)