From: Hrvoje Niksic
Subject: SETF intuitiveness? (was: Returning Functions)
Date: 
Message-ID: <kig201r1oex.fsf_-_@jagor.srce.hr>
······@world.std.com (Kent M Pitman) writes:

> SETF gets a litte messy, too.

I don't know which messiness you refer to here, but I'd like to show a
case where I find SETF (and it derivatives) a little-bit nonobvious,
with respect to how they work.  Take this expression, for instance:

  ...
  (incf (gethash function hash 0) numcalls)

A typical C user, when told about powers of Lisp optimizers, will
typically say: "Whee, this could be optimized beautifully -- the
code can find the pointer to the code, and simply increment it
(initializing it to zero, if necessary).  I don't know how these SETF
and INCF thingies work, but they sure are nice!"

Now, after learning about MACROEXPAND, our user may try to use it, and 
get something like:

;; CMUCL
(LET* ((#:G27 FUNCTION)
       (#:G28 HASH)
       (#:G29 0)
       (#:G30 (+ (GETHASH #:G27 #:G28 #:G29) NUMCALLS)))
  (%PUTHASH #:G27 #:G28 #:G30))

Of course, a good compiler can be instructed to optimize this, too --
but it definitely looks less promising than the above assumption.  In
general, Lisp seems to push an "I don't care how it works internally,
but Lisp compilers are good" approach that works well for building
abstractions, but may give wrong ideas.

I believe Richard Gabriel refers to something similar when he talks
about "knowledge of the implementation."

-- 
Hrvoje Niksic <·······@srce.hr> | Student at FER Zagreb, Croatia
--------------------------------+--------------------------------
"Psychos _do not_ explode when sunlight hits them."

From: Barry Margolin
Subject: Re: SETF intuitiveness? (was: Returning Functions)
Date: 
Message-ID: <61r5os$87b@pasilla.bbnplanet.com>
In article <··················@jagor.srce.hr>,
Hrvoje Niksic  <·······@srce.hr> wrote:
>  (incf (gethash function hash 0) numcalls)
>
>A typical C user, when told about powers of Lisp optimizers, will
>typically say: "Whee, this could be optimized beautifully -- the
>code can find the pointer to the code, and simply increment it
>(initializing it to zero, if necessary).  I don't know how these SETF
>and INCF thingies work, but they sure are nice!"

In fact, on Lisp Machines the expansion is very much like that.  Lisp
Machines have a primitive data type called "Locative", which is a GC-safe
pointer, and a LOCF operator that takes a "place" and returns a locative to
it.  The expansions of SETF, INCF, PUSH, etc. all make use of LOCF and
modify the object in place.  This also permitted the implementation of a
LETF macro that doesn't use UNWIND-PROTECT and interacts properly with
multithreaded programming.

In Lisp implementations without this kind of data type, it's difficult for
the SETF family of macros to optimize like this.  And of course, the macros
have to deal with user-defined place forms, and places like LDB that don't
refer to a real location.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
Support the anti-spam movement; see <http://www.cauce.org/>
Please don't send technical questions directly to me, post them to newsgroups.
From: Hrvoje Niksic
Subject: Re: SETF intuitiveness? (was: Returning Functions)
Date: 
Message-ID: <kigafgevvvc.fsf@jagor.srce.hr>
Barry Margolin <······@bbnplanet.com> writes:

> In article <··················@jagor.srce.hr>,
> Hrvoje Niksic  <·······@srce.hr> wrote:
> >  (incf (gethash function hash 0) numcalls)
> >
> >A typical C user, when told about powers of Lisp optimizers, will
> >typically say: "Whee, this could be optimized beautifully -- the
> >code can find the pointer to the code, and simply increment it
> >(initializing it to zero, if necessary).  I don't know how these SETF
> >and INCF thingies work, but they sure are nice!"
> 
> In fact, on Lisp Machines the expansion is very much like that.  Lisp
> Machines have a primitive data type called "Locative", which is a GC-safe
> pointer, and a LOCF operator that takes a "place" and returns a locative to
> it.  The expansions of SETF, INCF, PUSH, etc. all make use of LOCF and
> modify the object in place.  This also permitted the implementation of a
> LETF macro that doesn't use UNWIND-PROTECT and interacts properly with
> multithreaded programming.

This sounds interesting.  Why don't the Lisp compilers on non-LISPM
systems implement the "locative" data type (which would, I guess, boil 
down to pointers)?

-- 
Hrvoje Niksic <·······@srce.hr> | Student at FER Zagreb, Croatia
--------------------------------+--------------------------------
4.  Thou shalt not warlorde a sig if it bee the sig of Kibo, nor if
    it bee the sig of the Inner Circle.
From: Barry Margolin
Subject: Re: SETF intuitiveness? (was: Returning Functions)
Date: 
Message-ID: <61ubtq$69c@pasilla.bbnplanet.com>
In article <···············@jagor.srce.hr>,
Hrvoje Niksic  <·······@srce.hr> wrote:
>This sounds interesting.  Why don't the Lisp compilers on non-LISPM
>systems implement the "locative" data type (which would, I guess, boil 
>down to pointers)?

Mostly because the benefit isn't as great.  The LispM makes extensive use
of them for low-level system programming; their use with SETF is just an
added benefit.  Since other Lisp environments aren't implementing an entire
OS, they don't need such a feature as much.

Locatives complicate garbage collection.  Locatives allow you to have
pointers into the "middle" of composite objects, whereas "normal" Lisp
pointers can only point to the beginning of an object.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
Support the anti-spam movement; see <http://www.cauce.org/>
Please don't send technical questions directly to me, post them to newsgroups.
From: Erik Naggum
Subject: Re: SETF intuitiveness? (was: Returning Functions)
Date: 
Message-ID: <3085813927798089@naggum.no>
* Barry Margolin
| Locatives complicate garbage collection.  Locatives allow you to have
| pointers into the "middle" of composite objects, whereas "normal" Lisp
| pointers can only point to the beginning of an object.

would it be too much work and hassle to make a locative be a relative
pointer into a normal Lisp object?  (I'm thinking by analogy to displaced
arrays.)

#\Erik
-- 
if you think this year is "97", _you_ are not "year 2000 compliant".

see http://www.naggum.no/emacs/ for Emacs-20-related material.
From: Kent M Pitman
Subject: Re: SETF intuitiveness? (was: Returning Functions)
Date: 
Message-ID: <sfwk9fega1h.fsf@world.std.com>
Erik Naggum <······@naggum.no> writes:

> would it be too much work and hassle to make a locative be a relative
> pointer into a normal Lisp object?  (I'm thinking by analogy to 
> displaced arrays.)

If you look at the uses  to which locatives were put on the LispM you
find that most were system-critical non-consing situations.  In the
LispM architecture, one would simply get a pointer to a word of memory
with a locative pointer on it, but the point was that it was an immediate
object.  To be an offset object, it would have to have an ordinary
object plus an offset, which by definition means it's either not 
possible for all objects or else it is bigger than a normal object and
(hence) probably conses.  Frankly, if you don't mind consing, there are
a zillion ways for users to implement locatives with no system help;
so consing is the central barrier. 

And, in not consing, you probably have to involve the GC, too.  [e.g.,
Maclisp had MAKNUM and MUNKAM for getting an integer representing the
address of an object and MUNKAM for turning an integer into an object;
but then, Maclisp on the PDP10 didn't have a relocating GC and the
programmer had to worry about the GC implications of holding a pointer
as an integer which was GC opaque.  Locatives are a better way to go,
but the GC has to understand them...]

Anyway, for the most part, almost anything that can be done with a
locative can be done without, and that's why there has been no
pressure.  One use I used to like for locatives was:

 (defvar *cell* (let ((x (list nil))) (locf (car x))))

such that a cell was like a half-cons.  Something you could pass to
something in a kind of call-by-reference way and that the caller
could update in order to update all others pointing to that same
location.  A datatype half-cons (a HUNK1 in the parlance of the
post I sent last night on HUNKs) would be kind of useful sometimes
for cases when you're just passing a CONS for the purpose of having
something to side-effect but you only need the CAR and not the CDR.
(On the LispM also, you'd get only one cell allocation there because
of "cdr-coding"...)

Conceptually, the half-cons is meaningful as an indirect, by-reference
cell.  Sort of like an anonymous variable.  And I think implementations
could make an efficient implementation of that.

But requiring all implementations to efficiently implement locatives
would be a huge burden for probably very little computational gain.
From: Joerg Hoehle
Subject: Re: SETF intuitiveness? (was: Returning Functions)
Date: 
Message-ID: <61vui6$42s@omega.gmd.de>
Hrvoje Niksic (·······@srce.hr) wrote:
:   (incf (gethash function hash 0) numcalls)

: A typical C user, when told about powers of Lisp optimizers, will
: typically say: "Whee, this could be optimized beautifully -- the
: code can find the pointer to the code, and simply increment it
: (initializing it to zero, if necessary).  I don't know how these SETF
: and INCF thingies work, but they sure are nice!"

: Now, after learning about MACROEXPAND, our user may try to use it, and 
: get something like:

: ;; CMUCL
: (LET* ((#:G27 FUNCTION)
:        (#:G28 HASH)
:        (#:G29 0)
:        (#:G30 (+ (GETHASH #:G27 #:G28 #:G29) NUMCALLS)))
:   (%PUTHASH #:G27 #:G28 #:G30))

: Of course, a good compiler can be instructed to optimize this, too --
: but it definitely looks less promising than the above assumption.  In

Well, I understood CLtL II to say that implementations *must* provide
macroexpansions for all CLtL2 macros, so that one can happily program
code walkers, but their compilers are not required to use their own
macroexpansions when compiling CLtL2 macros, and a compiled (INCF
(GETHASH #)#) may well compute the hash code once only.  Or is mine
too weird a thought?

	Jo"rg Ho"hle.
············@gmd.de		http://zeus.gmd.de/~hoehle/amiga-clisp.html