From: Robert Kiendl
Subject: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <374148E2.9575B71C@gmx.net>
hi !

i am pretty new to the lisp community.  someone told me that lisp is the
language that provides quite every structural concept found in any other
language. also Paul Grahams introductory comments in "ANSI Common Lisp"
can get you delighted.
as far as i got insight to lisp up to now, it really seems to satisfy
many promises. especially in fields of versatile operator programing
(the term "functional programing" misleads in my opinion because it is
associated with restrictive mathematical mappings), dynamic structures
and types.

though i quickly can find fifty items where lisp is (much) more
"eloquent" and productive like for example c++, there remain few but
heavy scruples.

Besides things like 

- odd source code reading, which is a point of habit (i hope)
- low speed, which is not so heavy weight with modern compilers and
  c++-interfaces (for algorithms at the low level layer of the program)
- poor encapsulation formalism with respect to mind relieving          
OO-thinking (automatic object context, private/protected,    
overloading mechanisms ...), which is partially weight up by dynamic    
features and to the other part is (probably) an inevitable tribute
to       the versatile operator approach

there seem (to me) some "real" lacks. They mostly have to do with so
called missing "destruction automization" and the "hiding of the pointer
!type!"). The problem seems also to overlap with the coercion to the
"garbage collecting". 
Apart from simple things like e.g. a automatic CHideCursor"-object
(M...soft/MFC) i'll give an example deeper 
associated with expressiveness of a computer language.

In a simulation software i wrote (c++), there exist various objects (for
example MInfoAtom), where from many locations in the program (other
dynamic objects, globals, ...) is pointed to. Sometimes there is reason
the destroy those pointed-to-objects. the locations which point to
should be informed (for example - to set the pointers to 0). Its very
hard to book-keep those widespread non-uniform connections. therefore in
c++ i created a "reflecting pointer class template" (PR<class T>). 
the "PR-pointable-to" classes incorporate a simple uniform
Interface-class IPR ("class MInfoAtom: public other_base_classes, public
IPR"). 
If I want to define a reflective pointer i just write "PR<MInfoAtom>
mylink" instead of "MInfoAtom* mylink". the PR-Pointer class behaves
nearly like a normal pointer, i do not have to worry about during
writing code, i can also mix it with other pointers. I also use that new
pointers heavly inside of other template-containers (lists, maps,
queues, index-containers ...). they savely get informed by the mechanism
in the IPR-destructor interacting with PR<> when i make "delete myobj"
from anywhere. i also use complexer pointertypes like a PRH<class T>
which incorporates a share-holder concept. I use them all mostly like
normal pointers. The additional pointer properties are determined a the
definition location.
The software is "contaminated" with those "automatic links" and they
really do a good and efficient job preventing me from 
getting jumbled in the complex connection structure of the program. Also
the robustness of the software gained very much from that concept.

I can hardly imagine to rewrite such software not having this automatic
link concept at hand. 

With my lisp knowledge i do not see a handsome way to realize that
concept in lisp. I hope someone out there can tell me that its possible
anyhow.

There are some other scruples rooted mainly in the hiding of the pointer
type in lisp. but if someone can tell me a way to realize those
automatic links those scruples may also disapear. Bjarne Stroustroup
said, that it is dangerous to restrict language means just for the
intention of preventing from bugs (this prevention comes better from the
bottom up way: restrict where you like it). This is the reason for
example why JAVA is not a universal language suited for really complex
structured programs, though many poeple fascinated by the great network
and platform independent gui features think that.

My summarizing question is: Does the hiding of the pointer type and
garbage collection in the bottom up lisp language throw a shadow on the
space of expressiveness (analog to an area of disclosure of
computability in the sense of Goedel :-)) which comes apparent even on
the high level like for example in the above mentioned problem? Or is it
possible to enlight those area from the backdoor?

Or: Lisp is great on managing symbols and semantics of symbols. This
includes symbols which other languages have in the "code segment". But
is Lisp also great on connections (which do not suit in the hierarchy
paradigm)?

Robert
delphi creativ technologies

From: Erik Naggum
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <3136055673861525@naggum.no>
* Robert Kiendl <·······@gmx.net>
| i am pretty new to the lisp community.
:
| there seem (to me) some "real" lacks.

  which other disciplines do you consider yourself sufficiently well versed
  in to judge while you admit to being pretty new to them?  would you, say,
  walk into a hospital and tell the staff how to run the place?  would you
  take over the operating theater because you had seen a better way to do
  it on Chicago Hope?  do you, say, take the control of boats or planes?

  or would you perhaps try to learn first instead of judge first in other
  disciplines?

  I think the reason people find "lacks" with Lisp is that they actually
  expect everything in computing to be so simple they can understand it
  right away, since that's how things work in the mass market segments,
  where anyone with above average IQ is ahead of the "user-friendly" baby
  talk.  Lisp, however, is not optimized for newbies and well-below-average
  mass market consumers.  Lisp has its own traditions, far removed from the
  newbiedom that Microsoft, et al, have monopolized and capitalized on.

  my advice to those who are used to understanding much more than the user
  friendly crap intended them to do and thus acquire a haughtiness and
  arrogance towards new fields in computing that they might think are as
  stupidly designed as the ones they legitimately know better than, is to
  expect something different from what _looks_ different from what they're
  used to and to seize the opportunity to learn from the different rather
  than, effectively, to dumb it down to whatever they already understand
  much better than the designers.

  (if you felt insulted by the above, please give up Lisp, too.)

#:Erik
-- 
@1999-07-22T00:37:33Z -- pi billion seconds since the turn of the century
From: Jason Trenouth
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <37615475.341863968@newshost>
On Tue, 18 May 1999 13:02:58 +0200, Robert Kiendl <·······@gmx.net> wrote:

...

> In a simulation software i wrote (c++), there exist various objects (for
> example MInfoAtom), where from many locations in the program (other
> dynamic objects, globals, ...) is pointed to. Sometimes there is reason
> the destroy those pointed-to-objects. the locations which point to
> should be informed (for example - to set the pointers to 0). 

...

Perhaps you want something like weak pointers? Many GC'ed languages have a
notion of weak pointers. Basically, these pointers are not traversed for the
purposes of deciding what to retain when GCing. The result is that if you
throw away all normal references to an object, the object will be GC'ed
despite any weak references, and the weak references will be replaced by NIL
or somesuch value.

So one of your data structures might be modelled as, say, a "weak table"
containing your deleteable objects. Then when the responsible part of the
program deletes an object (e.g. by removing it from a normal table, leaving no
other references), the weak table will be updated by the GC to contain NIL.

Search your Lisp vendor's documentation for "weak".

__Jason
From: Tim Bradshaw
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <ey3hfpapmiu.fsf@lostwithiel.tfeb.org>
* Robert Kiendl wrote:

> I can hardly imagine to rewrite such software not having this automatic
> link concept at hand. 

> With my lisp knowledge i do not see a handsome way to realize that
> concept in lisp. I hope someone out there can tell me that its possible
> anyhow.

I think what you are after is an object which keeps track of all the
objects that reference it, so that when you `destroy' the object, it
can tell all the people that refer to it that it has been destroyed so
(in C++) you don't end up with dangling pointers.

Well, in Lisp you never destroy an object or end up with dangling
pointers as a result of that, but things along these lines are still
fairly useful, so you can at some point say `I want this to be GCable
now'.

I can see several ways of doing this in Common Lisp, of slightly
varying amounts of portability.

The simplest translation of your technique is to write a class which
deals with dependencies in this way, and then mix this in to all the
classes you are interested in.  Then the `I want to make this GCable'
operation on this object would end up doing something like:

	(map-dependents #'(lambda (d)
			    (remove-reference d o))
			o)

For this kind of thing it's quite nice if dependents are `weak' in
some way, so that an object doesn't end up holding onto references to
all sorts of transient things.  There is a dependency maintenance
protocol in the Art of the Metaobject Protocol book, and I have a
version of that somewhere if anyone is interested.


Another, slightly clunky, approach is to have the interesting object
be one extra indirection away, so you can then nullify that
indirection.  This is kind of steam weak-pointers -- the people
referencing the object still end up pointing to something, but that
something is hopefully a bunch cheaper than the original object (for
instance, a fixnum).

I often do this with hashtables (I've just typed this in, please don't
take it too seriously):

    (defvar *obhash* (make-hash-table))

    (defvar *obcount* 0)

    (defun make-avatar-for (ob)
      (setf (gethash *obcount* *obhash*) ob)
      (prog1 *obcount*
	(incf *obcount*)))

    (defun avatar-object (avatar)
      ;; 2nd value is `is it there?'
      (gethash avatar *obhash*))

    (defun remove-avatar-object (avatar)
      (remhash avatar *obhash*))

With an implementation like this, assuming you stick to less than a
fixnum-worth of objects, the avatars are pretty cheap, so the main
space cost is the hashtable, and the time cost is the hash lookup on
each reference.


Another, non-portable, approach would be to use weak pointers for the
references.  This is still quite hard work because you have to make
sure there is at least one strong reference to the object unless you
*really* want to be living in C++-land...


These approaches -- certainly the dependency stuff -- are pretty close
to some of the things that the design patterns people talk about.


> My summarizing question is: Does the hiding of the pointer type and
> garbage collection in the bottom up lisp language throw a shadow on the
> space of expressiveness (analog to an area of disclosure of
> computability in the sense of Goedel :-)) which comes apparent even on
> the high level like for example in the above mentioned problem? Or is it
> possible to enlight those area from the backdoor?

No, I don't think it does.

--tim
From: Lieven Marchand
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <m37lq61bt3.fsf@localhost.localdomain>
Robert Kiendl <·······@gmx.net> writes:

> i am pretty new to the lisp community.  someone told me that lisp is the
> language that provides quite every structural concept found in any other
> language. also Paul Grahams introductory comments in "ANSI Common Lisp"
> can get you delighted.
> as far as i got insight to lisp up to now, it really seems to satisfy
> many promises. especially in fields of versatile operator programing
> (the term "functional programing" misleads in my opinion because it is
> associated with restrictive mathematical mappings), dynamic structures
> and types.
> 

welcome aboard ;-)

> though i quickly can find fifty items where lisp is (much) more
> "eloquent" and productive like for example c++, there remain few but
> heavy scruples.
> 
> Besides things like 
> 
> - odd source code reading, which is a point of habit (i hope)

It is, and it is made easier by a very uniform way of indentation
among experienced Lisp programmers. Much of the homework code posted
here is simply not readable until formatted in the standard way.

> - low speed, which is not so heavy weight with modern compilers and
>   c++-interfaces (for algorithms at the low level layer of the program)

CL can be written to be very fast but the style in which you do it is
different. First you write your program as clearly as possible paying
attention to choice of algorithms, space/time trade offs etc and then,
*if* your application is too slow you can profile it and optimize the
hot spots by adding declarations or other means. There have been cases
cited on this group where a CL implementation tuned like this was
faster than a C/C++ implementation it replaced. Especially since you
cite MFC later on, MFC is many things but a speed daemon it is
certainly not ;-)

> - poor encapsulation formalism with respect to mind relieving          
> OO-thinking (automatic object context, private/protected,    
> overloading mechanisms ...), which is partially weight up by dynamic    
> features and to the other part is (probably) an inevitable tribute
> to       the versatile operator approach
> 

Again, I think you're approaching this from the wrong angle. Yes,
there are certain features (::, SLOT-VALUE) that can be used to
violate encapsulation, but nobody is forcing you to use them. All
access to slots can be done by accessors which are an alternative mean
to encapsulation. private/... can be done by selectively exporting in
different packages. (Not that you should try to write C++ in CLOS
syntax) If you worry that some coworker might use these features to
break your classes, the same can be done in C++

#define private public
#include "class.h"

[Note to C++ language lawyers, I know about the One Definition Rule
but this has a fair chance of working in practice]

The answer to such concerns is education and code review. No useful
language can shield you from such tricks.

> there seem (to me) some "real" lacks. They mostly have to do with so
> called missing "destruction automization" and the "hiding of the pointer
> !type!"). The problem seems also to overlap with the coercion to the
> "garbage collecting". 

In a way garbage collection is destruction automation. Theoretically
finalization is missing, although I wonder how useful it is in
practice. If you want to control stuff when an object becomes
unreachable, timing is usually also important. You don't want to wait
with closing file descriptors until your application exits, you want
to do it fairly soon after a stream object becomes unreachable.

And looked at in another way, everything in CL is a pointer.

-- 
Lieven Marchand <···@bewoner.dma.be>
If there are aliens, they play Go. -- Lasker
From: John Atwood
Subject: lisp pretty printer on files?
Date: 
Message-ID: <7hsedu$9fa$1@news.NERO.NET>
>> - odd source code reading, which is a point of habit (i hope)
>
>It is, and it is made easier by a very uniform way of indentation
>among experienced Lisp programmers. Much of the homework code posted
>here is simply not readable until formatted in the standard way.

How do I get code formatted in a standard way? 
I have an editor that'll format a block of code on command, but
I often view a file, only to find that it's not formatted to my
tastes.  I've read a little about Water's XP and chapter 22 of 
the HyperSpec concerning the Pretty Printer, it's too fine
grained. I'm seeking a way to format a file or list of files
according to one of a small set of pre-defined styles.  Emacs
probably does this, but I don't use emacs much; how would this
be done in emacs?


John Atwood
From: Christopher R. Barry
Subject: Re: lisp pretty printer on files?
Date: 
Message-ID: <87pv3xy3xm.fsf@2xtreme.net>
·······@bronze.CS.ORST.EDU (John Atwood) writes:

> I'm seeking a way to format a file or list of files according to one
> of a small set of pre-defined styles.  Emacs probably does this, but
> I don't use emacs much; how would this be done in emacs?

Emacs will _indent_ an entire buffer if you do C-x h to mark the
buffer and then C-M-\ to indent the region.

Christopher
From: Marc Battyani
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <D2C096BF0EF7D334.E07C0D408D074FEB.4DD00B6E5DFBCEC6@library-proxy.airnews.net>
Lieven Marchand <···@bewoner.dma.be> wrote in message
···················@localhost.localdomain...
> In a way garbage collection is destruction automation. Theoretically
> finalization is missing, although I wonder how useful it is in
> practice. If you want to control stuff when an object becomes
> unreachable, timing is usually also important. You don't want to wait
> with closing file descriptors until your application exits, you want
> to do it fairly soon after a stream object becomes unreachable.

I find finalization very useful for some UI objects like fonts pens
brushes OpenGL display lists etc..
When they are collected you have to free the underlying OS object also.
It's generally not worthwhile to bother to release them as soon
as possible.

Marc Battyani
From: Lieven Marchand
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <m3g14tnd7f.fsf@localhost.localdomain>
"Marc Battyani" <·············@csi.com> writes:

> I find finalization very useful for some UI objects like fonts pens
> brushes OpenGL display lists etc..
> When they are collected you have to free the underlying OS object also.
> It's generally not worthwhile to bother to release them as soon
> as possible.

Is there a limit on the number of allocated stuff like that? The main
problem I always saw was that if your OS had a limit, you could reach
that limit before garbage collection. But I agree when that's not the
case it can be useful.

-- 
Lieven Marchand <···@bewoner.dma.be>
If there are aliens, they play Go. -- Lasker
From: Erik Naggum
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <3136210989117825@naggum.no>
* Lieven Marchand <···@bewoner.dma.be>
| Is there a limit on the number of allocated stuff like that? The main
| problem I always saw was that if your OS had a limit, you could reach
| that limit before garbage collection. But I agree when that's not the
| case it can be useful.

  if the OS has such a limit, you should get an OS, or make the functions
  that allocate such objects cause a garbage collection, if you can't get
  an OS.  other people's limitations are to be overcome, not succumbed to.

#:Erik
-- 
@1999-07-22T00:37:33Z -- pi billion seconds since the turn of the century
From: Lieven Marchand
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <m3lnej7g6h.fsf@localhost.localdomain>
Erik Naggum <····@naggum.no> writes:

> * Lieven Marchand <···@bewoner.dma.be>
> | The main problem I always saw was that if your OS had a limit, you
> | could reach that limit before garbage collection.
>
>   if the OS has such a limit, you should get an OS, or make the
>   functions that allocate such objects cause a garbage collection,
>   if you can't get an OS.  other people's limitations are to be
>   overcome, not succumbed to.

The OS I'm currently using (Linux) has for instance, maximum number of
open files per process, maximum number of child processes per process,
and a whole number of similar limits, the values of some of which can
be queried by sysconf() and the value of others who can only be
guessed at. Is your limitless OS available somewhere?

--
Lieven Marchand <···@bewoner.dma.be>
If there are aliens, they play Go. -- Lasker
From: Tim Bradshaw
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <ey3n1yzjsbx.fsf@lostwithiel.tfeb.org>
* Lieven Marchand wrote:

> Is there a limit on the number of allocated stuff like that? The main
> problem I always saw was that if your OS had a limit, you could reach
> that limit before garbage collection. But I agree when that's not the
> case it can be useful.

However it's essentially trivial to cause hitting that limit to invoke
a GC.

--tim
From: Robert Kiendl
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <37459292.C5AD9287@gmx.net>
> > In a way garbage collection is destruction automation. Theoretically
> > finalization is missing, although I wonder how useful it is in
> > practice. If you want to control stuff when an object becomes
> > unreachable, timing is usually also important. You don't want to wait
> > with closing file descriptors until your application exits, you want
> > to do it fairly soon after a stream object becomes unreachable.
> 
> I find finalization very useful for some UI objects like fonts pens
> brushes OpenGL display lists etc..
> When they are collected you have to free the underlying OS object also.
> It's generally not worthwhile to bother to release them as soon
> as possible.

so ANSI common lisp really seems not to have means for real destruction
automation.
in fact that UI object example was just a hook for triggering the right
focus:
determinism. it misses the point discussing if we can release such
object sooner or 
later.

that PR-thing i mentioned uses the destruction automatism for data
structural purposes. deterministic finalization is used there to rise
essential information!
also this PR-thing was just one example. PR is not just used for set
references to nil, but also for more complex signals.
the second point was that PR is a type-expansion of a c++-pointer type.
so both things i wanted to mainly discuss in that letter come togehter
in that PR-example. thats why i brought this example: Both things -
destruction automation and the bottom up exposial of the pointer type to
the hands of the programmer - especially if they are used together they
provide some new space of expressiveness in the computer language. 

a few other guys brought into play that weak-vectors and so .... those
are not much more than fine excuse. 
1. they do not allow that program driven kill action. you'd have to have
alle "normal" references "weak" except one which "holds" and wich you
have again to publish widely to allow that kill access (indexes ...
�=$%?!). thats not applicable.
2. you have to worry about those special weak things (vectorref. even
for one element, ...). every location where you reference the object to
get into trouble. you cannot even automate this things completely by a
macro, because in lisp you cannot automate the behaviour of the type. so
you have to fumble in every sourcecode location, you cannot automate
this by one declaration (->hiding of the pointer type).
3. it is not ANSI - by good reason. it is thought for memory management
not as a structural mean. 

in fact i still have no idea how to transfer essential data structure
concepts of the simulation-code i mentioned into lisp without giving up
all the elegance
- strange that those problems are not a point of speed or low-level.

one little help would be at least if lisp would allow to explitely kill
a thing, setting all references to nil by force. because of the GC the
information for the necessary backlinks should be present in nearly
every implementation (am i right?). this capability would catch at least
the simplest behaviour of that PR-example.

so after receiving tons of new capabilities turning to lisp i'am getting
aware of some essential lacks (im comparison to e.g. c++) which you
cannot excuse with a c++-mindset. those lacks arise from
- weak destruction automation
- hiding of the nature of pointers
- mostly missing type-automation at the point of
declaration/instantiation 
also some bad encapsulation in CLOS (especially: no implizit object
context in methods) forces you to write some things redundantly, but
this is minor

robert
From: Steve Gonedes
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <m23e0qb2mn.fsf@KludgeUnix.com>
Robert Kiendl <·······@gmx.net> writes:
 
< that PR-thing i mentioned uses the destruction automatism for data
< structural purposes. deterministic finalization is used there to rise
< essential information!

There is a program that allows common lisp to be `deterministic', but
I cannot remeber the name right now - it's very popular and mentioned
quite often on this news group though...

[...]
 
< one little help would be at least if lisp would allow to explitely kill
< a thing, setting all references to nil by force.

(defvar *thing* "this is a thing")

(setq *thing* nil).

< so after receiving tons of new capabilities turning to lisp i'am getting
< aware of some essential lacks (im comparison to e.g. c++) which you
< cannot excuse with a c++-mindset. those lacks arise from
< - weak destruction automation

What is `weak destruction automation'?

< - mostly missing type-automation at the point of [...]

Could you give an example of `type-automation'? I have read the phrase
`type-automation', before but could not make sense of it. Have you
tried using the macro facility for automation of `type'?
From: Tim Bradshaw
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <ey3ogjez07j.fsf@lostwithiel.tfeb.org>
* Robert Kiendl wrote:

> one little help would be at least if lisp would allow to explitely kill
> a thing, setting all references to nil by force. because of the GC the
> information for the necessary backlinks should be present in nearly
> every implementation (am i right?). this capability would catch at least
> the simplest behaviour of that PR-example.

I still don't see why you can't do this with a dependency mechanism,
which must be basically similar to what you are doing in C++:

(defun kill (x &rest args)
   (map-dependents #'(lambda (d)
		       (apply #'release d x args))
	           x)
   (arrange-for-os-stuff-to-be-freed-for x)
   (values))

X may actually not go away at this point, but all the people who
referenced it no longer do so (assuming that's what RELEASE does).

--tim
From: Marc Battyani
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <30C20AA3AC755197.A47C46510E12B6E7.EAF8774974480B9B@library-proxy.airnews.net>
Robert Kiendl <·······@gmx.net> wrote in message
······················@gmx.net...
> that PR-thing i mentioned uses the destruction automatism for data
> structural purposes. deterministic finalization is used there to rise
> essential information!
> also this PR-thing was just one example. PR is not just used for set
> references to nil, but also for more complex signals.
> the second point was that PR is a type-expansion of a c++-pointer type.
> so both things i wanted to mainly discuss in that letter come togehter
> in that PR-example. thats why i brought this example: Both things -
> destruction automation and the bottom up exposial of the pointer type to
> the hands of the programmer - especially if they are used together they
> provide some new space of expressiveness in the computer language.
....

I don't see the point of all this. If you want to keep references to
parent/child
or friend objects you can. I do this very often. Then when you destroy/close
/modify etc this object you can have the other ones receive notifications
automatically .

> in fact i still have no idea how to transfer essential data structure
> concepts of the simulation-code i mentioned into lisp without giving up
> all the elegance

I've done it and now it's much more elegant than in C++.(and without bugs)

> so after receiving tons of new capabilities turning to lisp i'am getting
> aware of some essential lacks (im comparison to e.g. c++) which you
> cannot excuse with a c++-mindset. those lacks arise from
> - weak destruction automation
No see above.

> - hiding of the nature of pointers
Good!

> - mostly missing type-automation at the point of
> declaration/instantiation
Good too. In Lisp type information is used when needed. You don't
have to bother with this if you don't want to.

> also some bad encapsulation in CLOS (especially: no implizit object
> context in methods) forces you to write some things redundantly, but
> this is minor

This is not a lack but a feature. Generic functions are not methods on an
object.

Marc Battyani
From: Robert Kiendl
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <3748A89D.E4C1C5AC@gmx.net>
i hope it is not too boring for you all but my
problems representing some structures in lisp are still pending.
(maybe i should read more books, but if one puts my nose on the 
right point ...)

so i have to bring up some simple c++ example which lights one 
of the problems. the world of anmials often best animates 
programmers understanding so ...

[
the points of attention should be my skruples/concerns 
about lisp mentioned in the last mail:
>- weak destruction automation
>- hiding of the nature of pointers
>- mostly missing type-automation at the point of
   declaration/instantiation 
]

//(some Pxx code is at the end of the file if necessary)

//in our model we have birds

class MBase : public IPR, public IPH, public ... {...};
class MBird : public MBase
{
  ...
};

// we also have some world containers like
class MSky : public ...
{
  ...
  map<int, PRH<MBird> > birds ;		 // here they are
  d3_dictionary<MXYZ, PR<MBase> > space; // another index
  pqueue<double, PR<MBird> > interesting; // some of them i'm working on

  // we have some nice access:

  MBird* lookup(int id);
  list<MBase*> lookup(MShere& s) { ... care a little about NULL birds ... }

  // we do some normal work

  void step() { forall(MBird* it, birds) if (it) it->fly(); }

  ...
};

// somewhere is a camera
class VSky : public CView ...
{
  P<MSky> sky;			// we hold a sky
  // we have marked some 
  class VMark {
     ...
     list<PR<MBird> > birds;        
  } mark;
  ...
};

// somewhere is a hunter
class MHunter
{
  PE<MGun> gun;
  PR<MBird> focus;
  P<MBird> cage;
  MBird* aim() { return focus ? focus->danger++, focus : NULL };
//// speed annot.: if p is of type PR<> "p->a++" still compiles 
//// to one machine instruction	"inc  dword ptr [eax+4]" with -O2
//// despite of all that template stuff the compiler has to digest
  bool shoot(MBird* bird) {
    ...
    bird->pr_message("quiiick");
    return gun ? delete bird, true : false; // occasionally one disapears
  }
  ...
};

// there is also some global listener
static class __TEMP__ : public PR<MBird>
{
  virtual void message(char* s) {... protocol << s;  ...}
  ...
} microphone;
//////////////// birds birds birds ... //////////////////////

there are just few points that interest me about that shit:

- wenn sky terminates all birds also disapear immediately:
  no sky no birds. no one can even "quiick" any more. 
  the thing that makes it is the "..PRH.." in the map-definition.
  it says: you map will hold the birds. 
  [ in case a Java&Basic-GC-fan is out there: there is not any single 
    bird-delete in any of the "..."s. map<> and PRH<> do that;
    and please do not rise the circular-list-discussion here; if i 
    say hold i mean hold and not "don't worry"
  ]
  sometimes this is not totally correct; a bird can be both in the 
  sky and in a cage, in case such bird persists though there is no 
  sky (the ecologist may excuse that strange model but i want so).

  in lisp - shure - i know how to hold: the GC does it by default 
  anyway.
  [ i am just concerned a little bit about that uncertainty at the falling
    edge. may be spreading some gc-calls helps. someone told from other
    deterministic programs for lisp ...? but all this can discussed
    after first reading the rest ...
  ]
  but look at all the other bird-refs beside that single PRH. if i
  do them in lisp as normal things they all hold: the marker, the focus
  (, the index containers if not sky completely destructs), ...
  i do not want them to hold and
  i do not get rid of that shit 100's of cross referenced birds. the hunter 
  aims at that virtual reality bird and so on ...
  so i have to act:
  the only way _not_ to hold (99% of the other references above :-)) i 
  know now is using that non-ANSI weak stuff. 
  [ if i use that, do i have to everywhere fumble 
    svref's on the tables where i access 
    that references? (macro or not, i have to act at the access 
    points?)  your weak-let i think is for traversed functional
    bodies. or also for closures? but that temp and local locations are 
    not so troubling here.
    can i also do so at object positions [CLOS-slots, lying arround lists,
    ...] and let automate at the access points: e.g. using 
    (slot-value c 'my-variable) somewhere 5 kilometers source code away 
    not knowing if a weak-vector is in or not when passing to the next 
    action?! (the opposite i meant
    with "fumble": you have to at least trigger a read-char-macro, use special 
    access functions (-> i constantly must know about the weak nature)
    or so near the access point) 
    but anyway who wants express such essential stuff non-ANSI ?    
  ]
  or may be someone lateron tells me how to completely rearrange that whole 
  shit totally different in a lisp-oo-way, and all i said here about 
  holding and reflecting is completely unnecessary. so lets go further ...

- in that code above everywhere i handle and move around the birds by 
  simply by using them in the natural way (it->fly(), focus ? , 
  assignments, constructions, intermediate lists, p->a++, if (gun) ... . 
  special behaviour is expressed solely at the definition point.
  i think e.g.: my bird-refs in VMark must be informed, i use PR<>;
  my cage must share-hold the bird, i use P<>; my gun belongs to MHunter, 
  so use PE<>; ...
  i feed this concepts in once (in an aspect-oriented programming
  style!?) and do not think a lot about at the other 1000 times i access 
  and use the variables.

- i can shoot down a bird somewhere in the code in a consistent manner.
  [
    thats why i asked in the last mail for a _kill_ for lisp things and for
    that backlinks in the GC-mechanism 
    i think the backlinks exist at least in case of that weak stuff?
  ]
  [ this is not done by (defvar *thing* "this is a thing") (setq *thing* nil) 
    like someone mentioned; that doesn't kill the thing but the reference.
    its of course also not automated to do "delete" in the shoot-func, 
    i am not willing to automate a thing i intentionally want to rise. 
    a future AI program may be able to automate this but not this simple 
    code. what's automated is what happens in response to delete bird:
  ]
  the whole shit is informed of the disapearing bird (immediatly).
  neither in the shoot func nor in MBird-class i made explicite control
  for the necessary backlinks. i just fed in the above mentioned concepts
  at some declaration points. elsewhere i just wrote normal natural c++.
  [ microphone is also informed with other stuff than "delete"
    though it is just a type-expansion of a pointer; this is just an
    example to show what i mean with hiding of pointer in lisp.
    the pointer-thing in c++ can be treated as real type; of course one 
    can do that message shit other ways by writing some extra
    complex protocol code into MBird and a Listener Class, establishing 
    that multiple doubly link stuff, and so on. but the normal pointers 
    are already there anyway and i simple type-expand that PR-mechansim in 
    three local lines not fumbling anywhere else and can route the message
    through the same infrastructure than the delete.
  ]
- because mentioned things are automated in the types it is hard
  to write bugs concerning the interconnection properties. 
  if a basic/java programmer wants to represent above simple structure 
  - for example that shoot-capability - he gets crazy keeping track 
  of the interconnection semantics.
  this guides to that question in my first mail: "But is lisp also great 
  on connections (which do not suit in the hierarchy paradigm)?" in my 
  first mail.

so looking for example at that shit c++-example above and wanting to convert 
the structes (in a nonredundant style! if i have to explicitely write out 
interconnection semantics throughout the code or spread macro-chars and
special access-operators selectively over the mass of the code i am 
not far from Basic&Java.) to lisp there must be done something. may be 
in a completely different lisp way? how to ... thats was and is my 
question and i still don't see the way.
in some real c++ programs also some other aspectes of that 3 
mentioned points on the top of this file are important, but the key i think
is rooted in that bird example.

the lisp macros - down to the read-char-dispatch macros - are the best things 
in lisp. allowing nearly everything in the functional sense. here they
must be drilled to make data-type-automation. and perhaps they must be 
drilled to trick the limitation introduced by the coercion to the garbage
collecting (at least in ANSI CL). must they? if yes how?

robert

PS:
weaved in the above example is a way C++-mm resembles and even 
overcomes GC (by pure c++), thereby differentiating on the needs of
the objects. that is possible because c++ is providing languange level 
access to the pointer type (some overloading features) and allows
to really expand behaviour of types especially that pointer type. 
in opposite to for example java which has to live in the sandbox of
wood-blocks-LEGO(R)-OOP.
so it is also possible to bring up destruction automation for high-level
purposes stressed in the above example.

this 3 (or 4) things discussed in this file are of course only 3 of lets say
100 things a good programming language has to feature, most of them
best occupied by lisp (for a programmer who needs / wants / can deal with
those feateares in order to gain extra speeed)
thats why i use lisp. my question is if those things i stressed above form
a sort of "base vector" for programming languages which is not (so 
easily) substituable by combinations of other "vectors". (i am not
a mathematician!)

i really don't give up lisp. i just want discuss 3 aspects.
and i think lisp is a living language: you can discuss
about or at least ask questions.

------------------------------
Paul Foley schrieb:

> You can always release things "manually", like you have to in C++.
> Garbage collection should only be used as a backup mechanism for
> limited resources (e.g., you should close streams when you're done
> with them, rather than relying on the GC to do it, or you may run out
> of file descriptors before the GC recovers them)

can i release lisp things, not resources managed by lisp things?:

(setf a "thing")
  "thing"
(setf b a)
  "thing"
(____nonexistantkill____ b)
  ?
a
  nil

> > that PR-thing i mentioned uses the destruction automatism for data
> > structural purposes. deterministic finalization is used there to rise
> > essential information!
> 
> But it doesn't use any automation at all, does it...you have to use
> "delete" to free the thing you're concerned with.  Do the same thing
> in Lisp.

i mean things which happen in response to the destruction of an object
 
> > also this PR-thing was just one example. PR is not just used for set
> > references to nil, but also for more complex signals.
> 
> You can use Lisp weak pointers to do more complex things, using
> garbage collector hooks -- CMUCL uses them to implement post-GC
> finalizations, but that's not a good example; ACL has better
> finalization support, that can resurrect objects if that's what you
> want; finalization is another non-standardized feature that is usually
> available.

i do not want to resurrect i want to really kill and immediatly have rising 
automatic destructor execution. the above example shows that this can make 
sense.
ACL finalization doesn't get that PR-trick, because aslong as there is 
a single reference to the thing i will not get the thing finalizing.
weak-vectors are not the tool to design the mass of code with, i do yet not
see how to really get the weak-vector acceptably transparent to the language by 
macros, they are not ANSI, and they never will provide acceptable speed
(in the above example they would unfortunately have to do the job also of 
 normal c++ bird-pointers which are not "holding")
an other problem determinism remains and and and ...


> > the hands of the programmer - especially if they are used together they
> > provide some new space of expressiveness in the computer language.
> 
> I don't think so.  I'm willing to bet it's easier to implement
> whatever you're doing in Lisp that in C++ (and easier to understand
> when you do)

i cannot participate in your religion in at least 3 aspects up to now? 
but this may change ...

> > a few other guys brought into play that weak-vectors and so .... those
> > are not much more than fine excuse.
> > 1. they do not allow that program driven kill action. you'd have to have
> > alle "normal" references "weak" except one which "holds" and wich you
> > have again to publish widely to allow that kill access (indexes ...
> > �=$%?!). thats not applicable.
> 
> Weak pointers behave just like C++ pointers, but better -- you can
> delete the object they point to, but they then become NULL instead of
> pointing somewhere that will cause a segmentation fault when you try
> to dereference them.  Non-weak-pointer objects are like C++ (what do
> you call them?  References?  Things that you declare with "Foo &x;"
> that are really pointers but get dereferenced automatically.)
> 
> > 2. you have to worry about those special weak things (vectorref. even
> 
> You do in C++, too: you have to know when to say obj->foo and when to
> say obj.foo, don't you?

this comparison i think misses the point. the question of using "->" of "."
is more similiar to: using "'"-quote or not in lisp.
i do for example use "->" as well with "PR<A> a" as with "A* a".
"." doesn't have a counterpart in lisp because it means access to direct
embedding:

void func() {
  A a;
  a.x=3; 		//".x" accesses embedded context (on the stack)
  P<A> a2=new A(99);	//
  a2->x=3;		//this is conceptually the only thing lisp can do
			//though an aggressive lisp compiler may optimize it on 
			//the stack
  a2.ptr=0x123;		//this is an impact on embedded language 
			//internals on your own risk
}

class X {
  A a;
  A* a1;
  P<A>  a2;
  PE<A> a3;
  PR<A> a4;
  void func() { 
    a.x=3;  // ".x" accesses the embedded context (in the object)
    a1->x=3 // accesses external context
  }
  ...
}

this capability for differentiating between embedding and 
(various) dynamic interconnection relations immediatly
provides some special language expressiveness for no extra cost:
think about:

main()
{
  X x;	// X is the class above
  ....  //fill x somehow;
  X y=x;
}

x is copied (better:copy-constructed) there. c++ by default
makes it the right way:

a  is embedded so all the shit in it will be recursively copied.
a1 is just a naked informational link; just the reference will be copied.
a2 the obj will not be copied but then also share-holded by y;
   the share-holding status will be copied
a3 pseudo embedding PE automatically copies the obj as 
   in the a-case though the objects in fact resides in the heap! 
a4 the reflection status will be copied: if one kills or messages-to the 
   object later both x and y will be informed.

all this behaviour comes up in a natural way and is driven by
(again!) type-automation. 
special (more dynamic?) behaviour can by applied by a copy-constructor 
method. 
of course this latter case can be done in lisp even better. but the
former case with type-automation ...?
all this leads to some new questions i intended above with 
"...real c++ programs ...". but stop it here.

> > for one element, ...). every location where you reference the object to
> > get into trouble. you cannot even automate this things completely by a
> 
> Sure you can.
> 
>   (let ((foo (weak-vector 2)))
>     (symbol-macrolet ((obj1 (svref foo 0))
>                       (obj2 (svref foo 1)))
>        (setf obj1 object-1
>              obj2 object-2)
>        ...))
> 
> You could even write that as a macro to automatically bind any number
> of objects as weak pointers; e.g.
> 
>   (defmacro weak-let ((&rest bindings) &body body)
>     (let ((tmp (gensym)))
>       `(let ((,tmp (weak-vector ,(length bindings))))
>          (symbol-macrolet ,(loop for x in bindings as y from 0
>                               collect (list (car x) `(svref ,tmp ,y)))
>            (setf ,@(flatten bindings))
>            ,@body))))
> 
> and then use
> 
>   (weak-let ((obj1 object-1)
>              (obj2 object-2))
>      ...)
> 
> > in fact i still have no idea how to transfer essential data structure
> > concepts of the simulation-code i mentioned into lisp without giving up
> > all the elegance
> 
> If you give me more information on what you're trying to achieve, I
> might be able to provide some pointers (ha ha)
> 
> [In the worst case, you can do things exactly the same way you would
> do them in C++.]

maybe by simulating the memory. but in that sense a c++ guy can also simulate
lisps uniformity of code and data or even lisp itself what in fact is done in 
verious ways: most lisp-compilers itself and i also heard of a 
lisp-to-c-converter. one can bet which way would produce faster app code ...

> > one little help would be at least if lisp would allow to explitely kill
> > a thing, setting all references to nil by force. because of the GC the
> > information for the necessary backlinks should be present in nearly
> > every implementation (am i right?). this capability would catch at least
> > the simplest behaviour of that PR-example.
> 
> GC doesn't require keeping links to things, so no, there's not going
> to be a bunch of pointers joining things together.  If you want that,
> you can implement it, of course -- write your PR thing in Lisp.
> There's no law that says you have to use weak pointers, or any other
> standard or non-standard thing provided by your Lisp...if you decide
> the language doesn't already do what you need, write some code.

...

> The usual thing we do in Lisp is to define a macro for some limited
> resource FOO, traditionally called WITH-FOO, that allocates an
> instance of FOO for the duration of its body, and deallocates it when
> it finishes:
> 
>   (defmacro with-foo ((name &rest other-args) &body body)
>     `(let ((,name (allocate-a-foo ,@other-args)))
>        (unwind-protect
>            (progn ,@body)
>          (deallocate ,name))))

this is what i name operational expressiveness, which lisp
is best at. but such thing still doesn't allow binding the
unwinding on the solely to the type 

> The C++ equivalent is basically
> 
>   {
>      Foo <name>;
>      <body code>
>   }
> 

though in this diskussion the object context is in the focus
this functional(or "code block") context is also provides some 
light. say:

..
   ~A() { close(file); }
.. 
   ~B() ( if (condition) close(file); }
..

   {
     A a,a1,a2,a3;
     B b;
     {
       A a;
       ...
     }
   }

and compare this to the with-open-file's in corrisponding lisp
code;

in the c++ version you tell it to the A-class or the B-object that 
the file wants to be closed when the object goes out-of-scope 
(scope is possible 2 (3) ways: functional/block-context or 
object-context (or program context, but that is not a real new
quality)). its a property of the file-class/object. i don't
think anymore about: "there is a file to open and then to close"
the file is simply there in this context. the thinking is
really different! you may trying to automate the 4 a's in a chain
by an extra (functional!) macro, but you still think "there is a file
and that must be opened and then closed" at the point of work!

> or perhaps more correctly
> 
>   {
>      Foo *<name>;
>      <body code>
>      delete <name>;
>   }

this is C without ++ ( you may write better PE<Foo> )

> WITH-OPEN-FILE is an example in standard CL; it automatically closes
> the file when you're done.
> 
> > - hiding of the nature of pointers
> 
> Everything is a pointer in Lisp...what do you want to do with pointers
> that you can't do with Lisp objects?  Other than cause seg faults :-)

C style tends to seg faults. C++ tries to overcome without removing
language means. thats the old basic-java-argument ... in good C++ code
i am glad about a seg fault. by experience most time it directly points
to the bug. 

> > - mostly missing type-automation at the point of
> > declaration/instantiation
> 
> I know what you mean by this.  What do you want automated?  Are you
> talking about type declarations?  If you declare the return type(s) of
> your functions, Lisp can usually figure out what everything is
> (although most Lisps don't bother...CMUCL does a lot more type
> inferencing that other implementations).
> 
> > also some bad encapsulation in CLOS (especially: no implizit object
> > context in methods) forces you to write some things redundantly, but
> > this is minor
> 
> It's not bad encapsulation; there is, by design, no encapsulation in
> CLOS; and the nature of CLOS (multiple dispatch) makes it difficult to
> have object context -- a method isn't _in_ any object (it's in a
> generic function, but that's not very useful context)

ok, a macro-char which turns for example
  #?member-var 
into
  (slot-value this 'member-var)
or
  (member-var-accessor this)
provides a little bit automatic object context illusion/nostalgy
unless your focus isn't multiple dispatch ambiguous.
[ the distance is just 2 chars; is ist possible to get a distance
  of 0 chars (including bracket-chars) (don't mind CLOS or otherways?)
  allowing for example writing 
  (+ 3 member-var) inside a method body?
  i this case i suspect yes.
]

 
------------------------------------------------
some Pxx for clarity
------------------------------------------------
...
}; // core class P
 
class IPR;

/// PR_base : base class for PR<> 

template <class T> 
class PR_base					// besitzt keinen Zugriffsoperator !
{
	friend class IPR;
public:
	T* ptr;
	PR_base<T>* next;
#ifdef PR_DOUBLY
	PR_base<T>* prev;
#endif
#ifndef PR_NOINVALIDATE
	virtual void invalidate() {	/*printf("PR invalidates\n");*/ }
	//virtual void invalidate(void *it) {}
	virtual void message(char *s) {}
	//virtual ~PR_base() 	{}
#endif
};

/// PR<> core class

template <class T> 
class PR : public PR_base<T> {	// enth�lt keine Datenelemente
public:	
	PR(const PR<T>& other) {
		ptr=other.ptr;
		if (ptr) {
			next = (PR<T>*)(ptr->pr_head); 
#ifdef PR_DOUBLY
			if (ptr->pr_head) { ((PR<T>*)(ptr->pr_head))->prev=this; }
#endif
			ptr->pr_head=this;
		}
	}
	PR(const T *p = 0) {
		ptr=(T*)p;
		if (ptr) {
			next = (PR<T>*)(ptr->pr_head); 
#ifdef PR_DOUBLY
			if (ptr->pr_head) { ((PR<T>*)(ptr->pr_head))->prev=this; }
#endif
			ptr->pr_head=this;
		}
	}
    PR<T>& operator=(const PR<T>& other) {
		if (ptr==other.ptr) return *this;	// wenn ich schon gelinkt bin (indirekte
selbstzuweisung)
		release();
		ptr=other.ptr;
		if (ptr) {
			next = (PR<T>*)(ptr->pr_head); 
#ifdef PR_DOUBLY
			if (ptr->pr_head) { ((PR<T>*)(ptr->pr_head))->prev=this; }
#endif
			ptr->pr_head=this;
		}
		return *this;
	}
    PR<T>& operator=(const T *p) {
		release();
		ptr=(T*)p;
		if (ptr) {
			next = (PR<T>*)ptr->pr_head; 
#ifdef PR_DOUBLY
			if (ptr->pr_head) { ((PR<T>*)(ptr->pr_head))->prev=this; }
#endif
			ptr->pr_head=this;
		}
		return *this;
	}
	PR<T>& assign(T *p) {
		release();
		ptr=p;
		if (ptr) {
			next = (PR<T>*)ptr->pr_head; 
#ifdef PR_DOUBLY
			if (ptr->pr_head) { ((PR<T>*)(ptr->pr_head))->prev=this; }
#endif
			ptr->pr_head=this;
		}
		return *this;
	}
	~PR() { release(); }

    T& operator*() const { return *ptr; }
	T *operator->() const { return ptr; }
    T *get() const { return ptr; }
	void release() { // sich selbst aush�ngen aus der Liste
#ifndef PR_DOUBLY	
		PR_base<T>* p;
		void **pp;
#endif
		if (ptr) {
#ifdef PR_DOUBLY	// nur hier kommt der Vorteil von DOUBLY LINKED LIST zum tragen
			if (prev) prev->next=next; else ptr->pr_head=next;
			if (next) next->prev=prev;
#else
			for(pp=&ptr->pr_head,p=(PR<T>*)ptr->pr_head;    
			    p; 	
				pp=(void**)&p->next, p=p->next)

				if ( p==this ) { 
					*pp=p->next;	// sich selbst aush�ngen
					//ptr=0; nicht l�schen, da nicht n�tig und falsches Verhalten bei PRH<>
					break; 
				}
#endif
		}
	}
	operator T* () const { return ptr; }

};

/// Interface Class for PR<T>

class IPR {
public:
	void *pr_head;
public:
	IPR() : pr_head(0) {}
	IPR(const IPR &other) : pr_head(0) {}
	IPR &operator=(const IPR &other) 
	{
		// pr_head nicht zuweisen! (zugegeben, ein etwas seltsamer Zuweisungsoperator)
		return *this;
	}
	~IPR() { pr_invalidate(); } // invalidiere alle PR-pointer in der liste
	void pr_invalidate() {
		PR_base<int>* p=(PR_base<int>*)pr_head;
		for (;p;p=p->next) {
#ifndef PR_NOINVALIDATE
			p->invalidate(); // invalidate-Message f�r polymorphe Zwecke
#endif
			//printf("invalidate\n");
			p->ptr=0;
		}
	}
	void pr_redirect(void *pNew) {
		PR_base<IPR>* p=(PR_base<IPR>*)pr_head;
		for (;p;p=p->next) {
			p->ptr=(IPR*)pNew;
		}
	}
	void pr_message(char *s) {
		PR_base<IPR>* p=(PR_base<IPR>*)pr_head;
		for (;p;p=p->next) {
#ifndef PR_NOINVALIDATE
			p->message(s); // Message f�r polymorphe Zwecke
#endif
		}
	}
	PR_base<IPR>* pr_first() { return static_cast<PR<IPR> * >(pr_head); }
	PR_base<IPR>* pr_next(PR<IPR>* it) { return it->next; }
};


/// reflective & holding pointer

template <class T>
class PRH : public PR<T>
{
private:

	PRH(const PE<T>& other); // nicht erlaubt: Embedding Objekt kann nur von genau
einem PE gehalten werden
    PRH<T>& operator=(const PE<T>& other); // nicht erlaubt: Embedding Objekt
kann nur von genau einem PE gehalten werden

public:

	PRH(const PRH<T>& other) : PR<T>(other) {
		if (other.ptr) other.ptr->_p_counter++;
		//ptr=other.ptr;
	}
	PRH(T *p = 0) : PR<T>(p) {
		if (p) p->_p_counter++;
		//ptr=p;
	}
    PRH<T>& operator=(const PRH<T>& other) {
		T *p=other.ptr;			 // vorher zwischenspeichern, da bei release passieren kann,
da� &other.ptr ung�ltig wird!
		if (p) p->_p_counter++; // wichtig: vor dem release erh�hen, falls jemand
g1=g1 schreibt!
		T *pp=ptr;
		PR<T>::operator=(other);
		release(pp);
		//ptr=p;
		return *this;
	}
    PRH<T>& operator=(const PH<T>& other) {
		T *p=other.ptr;			 // vorher zwischenspeichern, da bei release passieren kann,
da� &other.ptr ung�ltig wird!
		if (p) p->_p_counter++; // wichtig: vor dem release erh�hen, falls jemand
g1=g1 schreibt!
		T *pp=ptr;
		PR<T>::operator=(p);
		release(pp);
		//ptr=p;
		return *this;
	}
    PRH<T>& operator=(PF<T>& other) {
		T *p=other.ptr;			// vorher zwischenspeichern, da bei release passieren kann,
da� &other.ptr ung�ltig wird!
		if (p) p->_p_counter++;	// wichtig: vor dem release erh�hen, falls jemand
g1=g1 schreibt!
		T *pp=ptr;
		PR<T>::operator=(other);
		release(pp);
		assert(other.fHold);
		other.fHold=false;
		//ptr=other.ptr;
		return *this;
	}
    PRH<T>& operator=(T *p) {
		if (p) p->_p_counter++;
		T *pp=ptr;
		PR<T>::operator=(p);
		release(pp);
		//ptr=p;
		return *this;
	}
	void assign(T* p) { 
		if (p) p->_p_counter++; 
		T *pp=ptr;
		PR<T>::assign(p);
		release(pp); 
		//ptr=p; 
	}
	~PRH() { release(ptr); }

    T& operator*() const { return *ptr; }
	T *operator->() const { return ptr; }
    T *get() const { return ptr; }
	void hold() { ptr->_p_counter++; }
	void release(T* ptr) {
		if (ptr) 
			if (!--ptr->_p_counter) {
				delete ptr; 
				//ptr=0; // eigentlich nicht n�tig
			}
	}
	operator T* () const { return ptr; }
};

/// embedding pointer

template <class T> class PE {
...
From: Steve Gonedes
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <m2n1yu3n38.fsf@KludgeUnix.com>
Robert Kiendl <·······@gmx.net> writes:
 
< - i can shoot down a bird somewhere in the code in a consistent manner.
<   [
<     thats why i asked in the last mail for a _kill_ for lisp things and for
<     that backlinks in the GC-mechanism 
<     i think the backlinks exist at least in case of that weak stuff?
<   ]
<   [ this is not done by (defvar *thing* "this is a thing") 
<        (setq *thing* nil) 

<     like someone mentioned; that doesn't kill the thing but the reference.
<     its of course also not automated to do "delete" in the shoot-func, 
<     i am not willing to automate a thing i intentionally want to rise. 
<     a future AI program may be able to automate this but not this simple 
<     code. what's automated is what happens in response to delete bird:
<   ]

I don't understand C++, so I don't know what your code does, but I
think I understand what you're trying to say. What I was trying to
demonstrate was that lisp provides no explicit, automatic pointer
manipulation; they're just handled automatically.

Perhaps this is more along the lines of what you're looking for?

(defclass object () ())
(defclass killed-object (object) ())
(defclass active-object (object) ())

(defmethod kill-object ((object object))
  (change-class object 'killed-object))

(defvar *object-x* (make-instance 'active-object))
(defvar *objects* (vector *object-x* *object-x*))
(defvar *object-x-ref* *object-x*)

*object-x*     => #<ACTIVE-OBJECT @ #x204f076a>
*objects*      => #(#1=#<ACTIVE-OBJECT @ #x204f076a> #1#)
*object-x-ref* => #<ACTIVE-OBJECT @ #x204f076a>

(kill-object *object-x*) => #<KILLED-OBJECT @ #x204f076a>

*object-x*     => #<KILLED-OBJECT @ #x204f076a>
*objects*      => #(#1=#<KILLED-OBJECT @ #x204f076a> #1#)
*object-x-ref* => #<KILLED-OBJECT @ #x204f076a>

The object has been killed. All references to the killed object refer
to the killed object.

You could of course define a method called delete on `object' if it
suits your needs better.
From: Kenny Tilton
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <374999D6.76D49CB5@liii.com>
Robert,

Robert Kiendl wrote:
> 
> i hope it is not too boring for you all but my
> problems representing some structures in lisp are still pending.
> (maybe i should read more books, but if one puts my nose on the
> right point ...)

Well, I will suggest two solutions, both of which you invite! :)

First, "more books": The Art of the Metaobject Protocol, ISBN
0-262-61074-4. That and a Lisp that fully supports the Metaobject
Protocol will get you going. And, FWIW, I rolled something of my own
under a Lisp that did not have such full MOP support and it would
achieve the same...Lisp can do anything. :)

With AMOP you can cook up slots that register themselves as "interested
parties" of cooperating slot-values, then write a function called
#'c++-delete to notify them when you want something to be forgtten.

Second, "may be someone lateron tells me how to completely rearrange
that whole..."

Hello! :) It strikes me you are mixing inappropriately wildly different
levels of expression. Specifically, you think the C++ 'delete' operator
is a way to kill a virtual bird.

No way! But C/C++ are so close to the hardware--and efficiency has
historically been so important--that programmers have always not only
expressed virtual states as machine states, but they make the natural
mistake of then thinking the machine impelementation is the same as the
virtual implementation, such that, getting back to the bird,
'delete-ing' it should kill it (in the virtual world).

I could not follow all of what you wrote (I am doing this on company
time) but I also wonder why you have so many pointers to this bird lying
around, but that doesn't matter.

Anyway, to a certain extent your question was not about how to kill
birds nor even how to manage internal dependencies, but about what Lisp
can do, so I think you might want to dig into AMOP if you have not
already.

Cheers,

kt
From: Tim Bradshaw
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <ey3hfozy56o.fsf@lostwithiel.tfeb.org>
I didn't really understand the C++ stuff in this thread (it's over 10
years since I did anything with C++ other than stare horrified at
it).  However I was inspired to try and see if I understood what was
going on, as some of it seems to be reasonably close to things I
already have.

Unfortunately the code I actually use is not releasable -- it doesn't
actually quite do this stuff and in any case it's pretty crufty stuff
I'm not that proud of. The attached code is just something I typed in
last night and shouldn't be taken very seriously. There's 2 layers of
it and a trivial example which uses the upper layer.

The bottom layer is a simple dependency class -- you can add & remove
(slowly) dependents and map over them.

The next layer is a class which can be told about people who `know
about it' and on being told to remove itself it will tell them do do
the appropriate thing (this uses double dispatch to avoid something
like the awful visitor pattern).  This also has a scope macro --
WITH-REMOVABLE-OBJECTS which will call the REMOVE-OBJECT GF at the end
of the dynamic scope of the macro.  Of course they still actually get
heap-allocated, perhaps some DYNAMIC-EXTENT declarations and a very
bright compiler could eliminate this (if you even wanted to).

Anyway, here it is, warts & all.

--tim

--cut--
;;; -*- Mode: LISP; Base: 10; Syntax: Ansi-common-lisp; Package: CL-USER -*-

;;;; Objects which have dependents.
;;; A fairly rudimentary implementation.
;;;

(defgeneric add-dependent (thing dependent)
  (:documentation
    "Register DEPENDENT as a dependent of THING, a subclass of DEPENDENCY-MIXIN.
Return DEPENDENT."))

(defgeneric remove-dependent (thing dependent)
  (:documentation
    "Remove a dependent of THING, a subclass of DEPENDENCY-MIXIN.
Return non-NIL if the thing was actually a dependent, tested with EQL"))

(defgeneric map-dependents (fn thing)
  (:documentation
    "Map FN, a function of one argument, over the dependencies of THING.
Return THING."))

(defclass dependency-mixin ()
    ((dependents :initform '())))

(defmethod add-dependent ((thing dependency-mixin) dependent)
  (push dependent (slot-value thing 'dependents))
  dependent)

(defmethod remove-dependent ((thing dependency-mixin) dependent)
  (with-slots (dependents) thing
    (let ((removedp nil))
      (setf dependents (delete dependent dependents
			       :test #'(lambda (x y)
					 (if (eql x y)
					       (setf removedp t)
					       nil))))
      removedp)))

(defmethod map-dependents (fn (thing dependency-mixin))
  (mapc fn (slot-value thing 'dependents))
  thing)


;;;; `Removable' objects (bad name).
;;; These are things which keep track of their owners and can inform
;;; them when they are removed.  They do this by virtue of being
;;; DEPENDENCY-MIXINs.
;;;

(defgeneric add-object-to (remob to)
  (:documentation
    "Add REMOB, an instance of a subclass of REMOVABLE-OBJECT, to TO.
No primary method is defined for this GF -- you need to define one for
your classes. REMOB will learn that TO knows about it via an after method.
Return value unspecified (up to you)."))

(defgeneric remove-object-from (remob from &optional internalp)
  (:documentation
    "Remove REMOB, an instance of a subclass of REMOVABLE-OBJECT, from FROM.
No primary method is defined for this GF -- you need to define one for
your classes.  The optional third argument is used internally and should
not be supplied in user-calls to this.  REMOB will already have learnt
that it is being removed when the primary method
runs.  Return value unspecified (up to you)."))

(defgeneric remove-object (remob &optional junkp)
  (:documentation
    "Remove a REMOVABLE-OBJECT.  If the optional JUNKP argument is given
then the object will be removed in a quick & dirty way, suitable if it's
about to be thrown away. No primary method is defined for this GF -- you
need to define one for your classes.  All the dependents of REMOB will
be told to remove it before the primary method runs.   Return value
unspecified (up to you)."))

(defclass removable-object (dependency-mixin)
    ())

(defmethod add-object-to :after ((remob removable-object) to)
  (add-dependent remob to))

(defmethod remove-object-from :before ((remob removable-object) from
				       &optional junkp)
  (unless junkp
    (remove-dependent remob from)))

(defmethod remove-object :before ((remob removable-object) &optional junkp)
  (map-dependents #'(lambda (d)
		      (remove-object-from remob d junkp))
		  remob))


(defmacro with-removable-objects (bindings &body bod)
  ;; this might be better implemented in terms of a CALL-WITH-x function
  `(let ,bindings
     (unwind-protect
	 (progn ,@bod)
       ,@(mapcar #'(lambda (n)
		     `(remove-object ,n t))
		 (mapcar #'car bindings)))))


;;;; Example use.
;;;

(defclass named-object ()
    ;; the standard thing-wth-a-name, to make tracing a bit nicer
    ((name :initform nil
	   :initarg :name
	   :reader name-of)))


(defclass bird (named-object removable-object)
    ()
  (:default-initargs
    :name "Edward"))

(defmethod remove-object ((b bird) &optional junkp)
  ;; Must define this.
  (declare (ignorable junkp))		;need to do this better
  (values))

(defclass birded-object ()
    ;; something that contains birds, like a sky or cage.
    ((birds :initform '()
	    :accessor birds)))

(defmethod add-object-to ((b bird) (to birded-object))
  ;; double dispatch, this whole thing would be a pain without this, you'd need
  ;; something like visitor.
  (push b (birds to)))

(defmethod remove-object-from ((b bird) (from birded-object)
			       &optional secret)
  ;; REMOVE-OBJECT-FROM' contract is buggy, either the optioal argument
  ;; needs better explained or it needs better concealed.
  (declare (ignorable secret))
  (setf (birds from) (delete b (birds from))))


;;; Tracing

(defmethod add-object-to :before ((b bird) (to birded-object))
  (format t "~& Adding ~A bird to ~A~%"
	  (name-of b) (name-of to)))

  
(defmethod remove-object-from :before ((b bird) (to birded-object)
				       &optional annoying)
  (declare (ignorable annoying))
  (format t "~& Removing ~A bird from ~A~%"
	  (name-of b) (name-of to)))

	  
(defclass sky (birded-object named-object)
    ()
  (:default-initargs
    :name "the sky"))

(defclass cage (birded-object named-object)
    ()
  (:default-initargs
    :name "a golden cage"))

(defun test-bird ()
  (let ((s (make-instance 'sky
			  :name "cloudy sky"))
	(c (make-instance 'cage
			  :name "rusty cage")))
    (with-removable-objects ((b (make-instance 'bird
					       :name "Louise")))
      (add-object-to b s)			;the bird is in the sky
      (add-object-to b c)			;and the cage
      (remove-object-from b s)
      (add-object-to b s)
      (values s c)
      ;; (and here the bird gets removed from the sky and the cage)
      )))
From: Johan Kullstam
Subject: Re: Lisp, the incarnation of expressiveness ...
Date: 
Message-ID: <ug14ui2wc.fsf@res.raytheon.com>
Robert Kiendl <·······@gmx.net> writes:

> hi !
> 
> i am pretty new to the lisp community.  someone told me that lisp is the
> language that provides quite every structural concept found in any other
> language. also Paul Grahams introductory comments in "ANSI Common Lisp"
> can get you delighted.
> as far as i got insight to lisp up to now, it really seems to satisfy
> many promises. especially in fields of versatile operator programing
> (the term "functional programing" misleads in my opinion because it is
> associated with restrictive mathematical mappings), dynamic structures
> and types.
> 
> though i quickly can find fifty items where lisp is (much) more
> "eloquent" and productive like for example c++, there remain few but
> heavy scruples.
> 
> Besides things like 
> 
> - odd source code reading, which is a point of habit (i hope)

you get used to it.  i am a lisp newbie.  now i find both lisp and C
to be weird looking.

> - low speed, which is not so heavy weight with modern compilers and
>   c++-interfaces (for algorithms at the low level layer of the
>   program)

the speed isn't as low as you seem to think.  good lisp compilers
exist.  lisp may add some overhead compared to C, but it won't
suddenly turn O(n) algorithms into O(n^2) algorithms.  you never know,
sometimes the lisp solution can be faster since you have a more simple
and direct way to express it.

> - poor encapsulation formalism with respect to mind relieving          
> OO-thinking (automatic object context, private/protected,    
> overloading mechanisms ...), which is partially weight up by dynamic    
> features and to the other part is (probably) an inevitable tribute
> to       the versatile operator approach

private/protected is imho overrated.  it just gets in your way without
helping much.  (if i could protect data in a C++ from getting nuked by
a stray pointer, *then* maybe i could see the point...)

> there seem (to me) some "real" lacks. They mostly have to do with so
> called missing "destruction automization" and the "hiding of the pointer
> !type!"). The problem seems also to overlap with the coercion to the
> "garbage collecting". 
> Apart from simple things like e.g. a automatic CHideCursor"-object
> (M...soft/MFC) i'll give an example deeper 
> associated with expressiveness of a computer language.
> 
> In a simulation software i wrote (c++), there exist various objects (for
> example MInfoAtom), where from many locations in the program (other
> dynamic objects, globals, ...) is pointed to. Sometimes there is reason
> the destroy those pointed-to-objects. the locations which point to
> should be informed (for example - to set the pointers to 0). Its very
> hard to book-keep those widespread non-uniform connections. therefore in
> c++ i created a "reflecting pointer class template" (PR<class T>). 
> the "PR-pointable-to" classes incorporate a simple uniform
> Interface-class IPR ("class MInfoAtom: public other_base_classes, public
> IPR"). 
> If I want to define a reflective pointer i just write "PR<MInfoAtom>
> mylink" instead of "MInfoAtom* mylink". the PR-Pointer class behaves
> nearly like a normal pointer, i do not have to worry about during
> writing code, i can also mix it with other pointers. I also use that new
> pointers heavly inside of other template-containers (lists, maps,
> queues, index-containers ...). they savely get informed by the mechanism
> in the IPR-destructor interacting with PR<> when i make "delete myobj"
> from anywhere. i also use complexer pointertypes like a PRH<class T>
> which incorporates a share-holder concept. I use them all mostly like
> normal pointers. The additional pointer properties are determined a the
> definition location.
> The software is "contaminated" with those "automatic links" and they
> really do a good and efficient job preventing me from 
> getting jumbled in the complex connection structure of the program. Also
> the robustness of the software gained very much from that concept.
> 
> I can hardly imagine to rewrite such software not having this automatic
> link concept at hand.

sure.  lisp keeps track of all this for you.  basically, you just stop
refering to something and it'll get reaped by the collector.  this is
an issue that the lisp vendor takes care of for you in their
implementation of the garbage collector.

if you do make some huge data structures and need to unload them, it
can be tricky to find all the referents, however.  i think this is
what you were trying to get at in your question.  i am sure that there
are tools to find what is using memory.  perhaps someone with better
lisp knowledge/experience can comment on how to track things down.
 
> With my lisp knowledge i do not see a handsome way to realize that
> concept in lisp. I hope someone out there can tell me that its possible
> anyhow.

*you* don't need to realize it all.  just lay back and accept it!  ;-)

> There are some other scruples rooted mainly in the hiding of the pointer
> type in lisp. but if someone can tell me a way to realize those
> automatic links those scruples may also disapear. Bjarne Stroustroup
> said, that it is dangerous to restrict language means just for the
> intention of preventing from bugs (this prevention comes better from the
> bottom up way: restrict where you like it). This is the reason for
> example why JAVA is not a universal language suited for really complex
> structured programs, though many poeple fascinated by the great network
> and platform independent gui features think that.

> My summarizing question is: Does the hiding of the pointer type and
> garbage collection in the bottom up lisp language throw a shadow on
> the space of expressiveness (analog to an area of disclosure of
> computability in the sense of Goedel :-)) which comes apparent even
> on the high level like for example in the above mentioned problem?
> Or is it possible to enlight those area from the backdoor?

in my (limited) experience with lisp, low level cruft just doesn't
come up as an issue.  i can do what i like.  i don't worry about
memory allocation.  i have a hard enough time trying to phrase things
properly.  i find lisp to be totally backwards when coming from
languages such as C and fortran.  (i don't mean lisp is wrong, it's
just different.  i get the feeling of standing on my head since i have
spent many years hard wiring myself into C/C++.)

> Or: Lisp is great on managing symbols and semantics of symbols. This
> includes symbols which other languages have in the "code segment". But
> is Lisp also great on connections (which do not suit in the hierarchy
> paradigm)?

what do you mean `connections'?

> Robert
> delphi creativ technologies

-- 
johan kullstam