From: Marcin Tustin
Subject: Destructors
Date: 
Message-ID: <yztbvg8fjlgq.fsf@vampire.i-did-not-set--mail-host-address--so-shoot-me>
    Is there a way of defining object destructors in CLOS? 
I'd like to have a "create and forget" way of dealing with
sockets, and this would be just the thing.

-- 
You're trapped in my mental fog box! I'm gonna tear you up with this shit!!!

From: Christopher C. Stacy
Subject: Re: Destructors
Date: 
Message-ID: <ubsa76wb3.fsf@grant.org>
>>>>> On 19 Jun 2002 17:13:09 +0100, Marcin Tustin ("Marcin") writes:

 Marcin>     Is there a way of defining object destructors in CLOS? 
 Marcin> I'd like to have a "create and forget" way of dealing with
 Marcin> sockets, and this would be just the thing.

You mean you have some protocol that doesn't know when you're
closing the socket?  If you know when you close it, then isn't
that when you want to do your finalizations?  Or, if you don't
explicitly close it, how would it ever become eligable for
garbage collection and finalization?
From: Vlastimil Adamovsky
Subject: Re: Destructors
Date: 
Message-ID: <3d10bf56$1_1@nntp2.nac.net>
I have the same question as Marcin...
If an object is not referenced by anybody, how can I run a "destruction"
code?
It is necessary for releasing external resources..

Vlastik


"Christopher C. Stacy" <······@grant.org> wrote in message
··················@grant.org...
> >>>>> On 19 Jun 2002 17:13:09 +0100, Marcin Tustin ("Marcin") writes:
>
>  Marcin>     Is there a way of defining object destructors in CLOS?
>  Marcin> I'd like to have a "create and forget" way of dealing with
>  Marcin> sockets, and this would be just the thing.
>
> You mean you have some protocol that doesn't know when you're
> closing the socket?  If you know when you close it, then isn't
> that when you want to do your finalizations?  Or, if you don't
> explicitly close it, how would it ever become eligable for
> garbage collection and finalization?
>
From: Marco Antoniotti
Subject: Re: Destructors
Date: 
Message-ID: <y6cn0trazwf.fsf@octagon.mrl.nyu.edu>
"Vlastimil Adamovsky" <·····@ambrasoft.com> writes:

> I have the same question as Marcin...
> If an object is not referenced by anybody, how can I run a "destruction"
> code?
> It is necessary for releasing external resources..

What external resources?

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Vlastimil Adamovsky
Subject: Re: Destructors
Date: 
Message-ID: <3d116c22$1_2@nntp2.nac.net>
"Marco Antoniotti" <·······@cs.nyu.edu> wrote in message
····················@octagon.mrl.nyu.edu...
>
> "Vlastimil Adamovsky" <·····@ambrasoft.com> writes:
>
> > I have the same question as Marcin...
> > If an object is not referenced by anybody, how can I run a "destruction"
> > code?
> > It is necessary for releasing external resources..
>
> What external resources?

For example a piece of memory allocated in a computer somewhere in other
country...

>
> Cheers
>
> --
> Marco Antoniotti ========================================================
> NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
> 719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
> New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
>                     "Hello New York! We'll do what we can!"
>                            Bill Murray in `Ghostbusters'.
From: Marco Antoniotti
Subject: Re: Destructors
Date: 
Message-ID: <y6c7kkudo6j.fsf@octagon.mrl.nyu.edu>
"Vlastimil Adamovsky" <·····@ambrasoft.com> writes:

> "Marco Antoniotti" <·······@cs.nyu.edu> wrote in message
> ····················@octagon.mrl.nyu.edu...
> >
> > "Vlastimil Adamovsky" <·····@ambrasoft.com> writes:
> >
> > > I have the same question as Marcin...
> > > If an object is not referenced by anybody, how can I run a "destruction"
> > > code?
> > > It is necessary for releasing external resources..
> >
> > What external resources?
> 
> For example a piece of memory allocated in a computer somewhere in other
> country...

Well, in this case you have the following cases in C++.

1 - You have your "owner" instance allocated on the stack.
2 - You have your "owner" instance allocated on the heap.

In case 1 you can rely on the destructor to be invoked "at the right
time" (quotes mandatory).  In case 2 you are calling the destructor
"at the right time" by manually using `delete' somewhere in your code.

Case 1 in CL is handled by WITH-* macros expanding in the correct
UNWIND-PROTECT code.  Case 2 is handled by writing some code that
destroys the instance (and the container).  Nobody prevents you from
writing your own

        (defmethod my-package:destroy ((x some-class)) ...)

and make sure that it is called within the WITH-* macro and/or in the
more complex DELETE-INSTANCES-CONTAINER.

Here is the skeletal code for it

        (defmethod delete-instances-container ((l list))
           (dolist (e l) (destroy e)))

        (defmethod delete-instances-container ((s sequence))
           (loop for x from 0 below (length s)
                 for y = (elt s i)
                    do (destroy y)))

        (defmethod delete-instaces-container ((h hash-table))
           (loop for v being the hash-value of h
                 do (destroy x)))


The method for multi-dimensional arrays is left as an exercise to the
reader :)

All in all this is just a different protocol than that based on
destructors.

Having said that, I agree that a FINALIZE method would be nice to have.

Cheers


-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Vlastimil Adamovsky
Subject: Re: Destructors
Date: 
Message-ID: <3d12ab29_1@nntp2.nac.net>
Thanks for help....
I am an experienced Smalltalk and C++ (I think) and
I just "discovered" Lisp as an interesting language....
I am just starting diving into Lisp waters, that's why I may
have stupid questions (sometimes)...

Further more, I have doscovered that Lisp is amazingly closed
to my way of thinking (I think)...

And also I have discovered, the Lisp language is addictive....


Vlastik


"Marco Antoniotti" <·······@cs.nyu.edu> wrote in message
····················@octagon.mrl.nyu.edu...
>
> "Vlastimil Adamovsky" <·····@ambrasoft.com> writes:
>
> > "Marco Antoniotti" <·······@cs.nyu.edu> wrote in message
> > ····················@octagon.mrl.nyu.edu...
> > >
> > > "Vlastimil Adamovsky" <·····@ambrasoft.com> writes:
> > >
> > > > I have the same question as Marcin...
> > > > If an object is not referenced by anybody, how can I run a
"destruction"
> > > > code?
> > > > It is necessary for releasing external resources..
> > >
> > > What external resources?
> >
> > For example a piece of memory allocated in a computer somewhere in other
> > country...
>
> Well, in this case you have the following cases in C++.
>
> 1 - You have your "owner" instance allocated on the stack.
> 2 - You have your "owner" instance allocated on the heap.
>
> In case 1 you can rely on the destructor to be invoked "at the right
> time" (quotes mandatory).  In case 2 you are calling the destructor
> "at the right time" by manually using `delete' somewhere in your code.
>
> Case 1 in CL is handled by WITH-* macros expanding in the correct
> UNWIND-PROTECT code.  Case 2 is handled by writing some code that
> destroys the instance (and the container).  Nobody prevents you from
> writing your own
>
>         (defmethod my-package:destroy ((x some-class)) ...)
>
> and make sure that it is called within the WITH-* macro and/or in the
> more complex DELETE-INSTANCES-CONTAINER.
>
> Here is the skeletal code for it
>
>         (defmethod delete-instances-container ((l list))
>            (dolist (e l) (destroy e)))
>
>         (defmethod delete-instances-container ((s sequence))
>            (loop for x from 0 below (length s)
>                  for y = (elt s i)
>                     do (destroy y)))
>
>         (defmethod delete-instaces-container ((h hash-table))
>            (loop for v being the hash-value of h
>                  do (destroy x)))
>
>
> The method for multi-dimensional arrays is left as an exercise to the
> reader :)
>
> All in all this is just a different protocol than that based on
> destructors.
>
> Having said that, I agree that a FINALIZE method would be nice to have.
>
> Cheers
>
>
> --
> Marco Antoniotti ========================================================
> NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
> 719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
> New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
>                     "Hello New York! We'll do what we can!"
>                            Bill Murray in `Ghostbusters'.
From: Brad Miller
Subject: Re: Destructors
Date: 
Message-ID: <aevogc$pl2$1@newshost.mot.com>
Check out the resources package that is part of CL-LIB on
ftp.cs.rochester.edu or resources.lisp on the CMU repository. (Or I can
email you the most recent version.) This is a portable implementation of the
LispM resources, which essentially lets you roll your own memory management,
and in particular will allow you to have code run when you release something
back to the pool.

Best,

"Vlastimil Adamovsky" <·····@ambrasoft.com> wrote in message
···············@nntp2.nac.net...
> Thanks for help....
> I am an experienced Smalltalk and C++ (I think) and
> I just "discovered" Lisp as an interesting language....
> I am just starting diving into Lisp waters, that's why I may
> have stupid questions (sometimes)...
>
> Further more, I have doscovered that Lisp is amazingly closed
> to my way of thinking (I think)...
>
> And also I have discovered, the Lisp language is addictive....
>
>
> Vlastik
>
>
> "Marco Antoniotti" <·······@cs.nyu.edu> wrote in message
> ····················@octagon.mrl.nyu.edu...
> >
> > "Vlastimil Adamovsky" <·····@ambrasoft.com> writes:
> >
> > > "Marco Antoniotti" <·······@cs.nyu.edu> wrote in message
> > > ····················@octagon.mrl.nyu.edu...
> > > >
> > > > "Vlastimil Adamovsky" <·····@ambrasoft.com> writes:
> > > >
> > > > > I have the same question as Marcin...
> > > > > If an object is not referenced by anybody, how can I run a
> "destruction"
> > > > > code?
> > > > > It is necessary for releasing external resources..
> > > >
> > > > What external resources?
> > >
> > > For example a piece of memory allocated in a computer somewhere in
other
> > > country...
> >
> > Well, in this case you have the following cases in C++.
> >
> > 1 - You have your "owner" instance allocated on the stack.
> > 2 - You have your "owner" instance allocated on the heap.
> >
> > In case 1 you can rely on the destructor to be invoked "at the right
> > time" (quotes mandatory).  In case 2 you are calling the destructor
> > "at the right time" by manually using `delete' somewhere in your code.
> >
> > Case 1 in CL is handled by WITH-* macros expanding in the correct
> > UNWIND-PROTECT code.  Case 2 is handled by writing some code that
> > destroys the instance (and the container).  Nobody prevents you from
> > writing your own
> >
> >         (defmethod my-package:destroy ((x some-class)) ...)
> >
> > and make sure that it is called within the WITH-* macro and/or in the
> > more complex DELETE-INSTANCES-CONTAINER.
> >
> > Here is the skeletal code for it
> >
> >         (defmethod delete-instances-container ((l list))
> >            (dolist (e l) (destroy e)))
> >
> >         (defmethod delete-instances-container ((s sequence))
> >            (loop for x from 0 below (length s)
> >                  for y = (elt s i)
> >                     do (destroy y)))
> >
> >         (defmethod delete-instaces-container ((h hash-table))
> >            (loop for v being the hash-value of h
> >                  do (destroy x)))
> >
> >
> > The method for multi-dimensional arrays is left as an exercise to the
> > reader :)
> >
> > All in all this is just a different protocol than that based on
> > destructors.
> >
> > Having said that, I agree that a FINALIZE method would be nice to have.
> >
> > Cheers
> >
> >
> > --
> > Marco Antoniotti
========================================================
> > NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
> > 719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
> > New York, NY 10003, USA
http://bioinformatics.cat.nyu.edu
> >                     "Hello New York! We'll do what we can!"
> >                            Bill Murray in `Ghostbusters'.
>
>
From: Barry Margolin
Subject: Re: Destructors
Date: 
Message-ID: <_Z3Q8.9$0%3.552@paloalto-snr1.gtei.net>
In article <············@nntp2.nac.net>,
Vlastimil Adamovsky <·····@ambrasoft.com> wrote:
>I have the same question as Marcin...
>If an object is not referenced by anybody, how can I run a "destruction"
>code?
>It is necessary for releasing external resources..

Many implementations have a feature called "finalization", but it's not a
part of standard Common Lisp.  Check your documentation for the details.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Brian Spilsbury
Subject: Re: Destructors
Date: 
Message-ID: <f0f9d928.0206192349.1b1b0873@posting.google.com>
"Vlastimil Adamovsky" <·····@ambrasoft.com> wrote in message news:<············@nntp2.nac.net>...
> I have the same question as Marcin...
> If an object is not referenced by anybody, how can I run a "destruction"
> code?
> It is necessary for releasing external resources..
> 
> Vlastik

While I tend to prefer (with- ... ) forms which make this explicit,
sometimes it is nice to have clean-up code for objects with indefinite
extent.

There is no standard way to do this in CL afaik, but finalisers are
supported by many implementations, and if your implementation supports
weak-references and post-gc handlers, then you can implement
finalisers yourself if necessary.

Ie, keep a list of weak-references and associated functions, when a
weak-reference breaks after a gc, then call the associated function.

Note that this means that the object you are finalising for has
already been garbage-collected, so your finaliser needs to be able to
run without addressing this object, but given closures, this is pretty
easy.

If you're finding a common need for this kind of thing, then you're
probably using a poor design - the main use for things like this is to
close unix fd's and so on when wrappers are collected.

Regards,

Brian
From: Thomas F. Burdick
Subject: Re: Destructors
Date: 
Message-ID: <xcvvg8dyh4h.fsf@conquest.OCF.Berkeley.EDU>
·····@designix.com.au (Brian Spilsbury) writes:

> "Vlastimil Adamovsky" <·····@ambrasoft.com> wrote in message news:<············@nntp2.nac.net>...
> > I have the same question as Marcin...
> > If an object is not referenced by anybody, how can I run a "destruction"
> > code?
> > It is necessary for releasing external resources..
> > 
> > Vlastik
> 
> While I tend to prefer (with- ... ) forms which make this explicit,
> sometimes it is nice to have clean-up code for objects with indefinite
> extent.

But it better not be important that it run, because it's entirely
likely that it won't ever run.  If it's actually that difficult to
figure out what the object's extent is, I'd say it's got a very good
chance of landing itself in a tenured generation and never being
collected.

And the only way aroud that problem is to use non-generational GC.
For most purposes, the cure sounds worse than the disease.

> If you're finding a common need for this kind of thing, then you're
> probably using a poor design - the main use for things like this is to
> close unix fd's and so on when wrappers are collected.

This would be a good time to add that it's a good idea to /have/
finalizers for things like closing fd's, but it's a terrible idea to
rely on them.  As a last-chance safety mechanism that writes an error
in a log file, it's a good idea, though.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Carl Shapiro
Subject: Re: Destructors
Date: 
Message-ID: <ouyn0tpri27.fsf@panix3.panix.com>
·····@designix.com.au (Brian Spilsbury) writes:

> If you're finding a common need for this kind of thing, then you're
> probably using a poor design - the main use for things like this is to
> close unix fd's and so on when wrappers are collected.

Using a GC finalizer to manage file descriptors is actually a great
way to get yourself into trouble.  File descriptors should be closed
as soon as they go out of scope, not when the object they are
associated with becomes unreachable.
From: Barry Margolin
Subject: Re: Destructors
Date: 
Message-ID: <fRoQ8.18$KJ6.1427@paloalto-snr1.gtei.net>
In article <···············@panix3.panix.com>,
Carl Shapiro  <·············@panix.com> wrote:
>·····@designix.com.au (Brian Spilsbury) writes:
>
>> If you're finding a common need for this kind of thing, then you're
>> probably using a poor design - the main use for things like this is to
>> close unix fd's and so on when wrappers are collected.
>
>Using a GC finalizer to manage file descriptors is actually a great
>way to get yourself into trouble.  File descriptors should be closed
>as soon as they go out of scope, not when the object they are
>associated with becomes unreachable.

Right.  Garbage collection is too non-deterministic.  Unless you explicitly
call (GC), you never know when it's going to happen.  Furthermore, it's
much too easy to leave references lying around (perhaps the structure was
returned to the REPL at some time, so it's being held in a history list).

They can be used to CYA, so that resources get cleaned up if the program
forgets to call the cleanup routine before dropping all the references.
But you should not *depend* on them for routine cleanups.  Perhaps the best
use of them would be during development: have the finalizer print a warning
if it's invoked, so that you can figure out why you forgot to clean up the
resource.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kaz Kylheku
Subject: Re: Destructors
Date: 
Message-ID: <af8deq$jpn$1@luna.vcn.bc.ca>
In article <············@nntp2.nac.net>, Vlastimil Adamovsky wrote:
> I have the same question as Marcin...
> If an object is not referenced by anybody, how can I run a "destruction"
> code?
> It is necessary for releasing external resources..

The answer is that you don't know when garbage collection will happen.  So even
if there were a way to run a destruction routine at that time (as for instance,
finalization in Java), it's quite likely that it is too late. Resources have to
be released in a timely way. For example, you don't want to keep a file or a
network connection open indefinitely! It's a bad idea to *want* to just forget
about a socket. You cannot do that, because the state of your socket is visible
to the world; whether or not you close the socket or file is an externally
visible behavior of your program, unlike memory management, which is purely
internal. 

The solution is to run whatever clean up is needed, and just leave behind
the object which holds the handles to these resources. That object's storage
will be collected. 

The unwind-protect form is your friend, at least for cleaning up resources
whose duration is to be tied to the evaluation of a form. unwind-protect
can be hidden behind a macro interface. Take a look at some of the standard
WITH- macros in Common Lisp like with-open-file.  This one internally creates a
stream associated with an open file, executes your forms with a variable bound
to that stream and then closes the file. Code that uses with-open-file cannot
leak file handles unless the implementation of that macro is broken.
From: Joel Ray Holveck
Subject: Re: Destructors
Date: 
Message-ID: <y7cznxe4x07.fsf@sindri.juniper.net>
> I have the same question as Marcin...
> If an object is not referenced by anybody, how can I run a "destruction"
> code?
> It is necessary for releasing external resources..

Every time I see a question about finalization, I hear lots of
admonition about what it shouldn't be used for.  So, what would be an
appropriate use of finalization?

I hear "external resources", but "not Unix FDs", which are possibly
the most forgiving external resource I can think of.  So what would be
an external resource for which finalization would be appropriate?

Thanks,
joelh
From: Kaz Kylheku
Subject: Re: Destructors
Date: 
Message-ID: <afjavp$c0l$1@luna.vcn.bc.ca>
In article <···············@sindri.juniper.net>, Joel Ray Holveck wrote:
>> I have the same question as Marcin...
>> If an object is not referenced by anybody, how can I run a "destruction"
>> code?
>> It is necessary for releasing external resources..
> 
> Every time I see a question about finalization, I hear lots of
> admonition about what it shouldn't be used for.  So, what would be an
> appropriate use of finalization?

They are for just-in-case cleanup after sloppy programming. That is
one explanation for their inclusion in the Java language.

What you can do with a finalizer is place an assertion in it which signals an
error if it finds the object to be other than cleaned up. Kind of like a
mortician checking for any signs of life before replacing the blood with
formaldehyde. ;)

> I hear "external resources", but "not Unix FDs", which are possibly
> the most forgiving external resource I can think of.

They are? Failing to close a device driver might make the device unavailable to
other processes, including the same one which didn't do it! Failing to close a
tty might fail to hang up a modem.  Failing to close or shutdown a socket
results in a connection remaining open, and ports being occupied.  You may run
out of descriptors if you generate too many open file descriptors before the
next garbage collection happens (GC probably won't be triggered on the
condition of running out of descriptors!) Descriptors that refer to open file
inodes prevent those inodes from being recycled and their data blocks from
being reassigned to other files, so your process could occupy, at least
temporarily, more disk space than you intended.
From: Joe Marshall
Subject: Re: Destructors
Date: 
Message-ID: <Y9bT8.342189$352.40764@sccrnsc02>
"Kaz Kylheku" <···@ashi.footprints.net> wrote in message ·················@luna.vcn.bc.ca...
>
> GC probably won't be triggered on the
> condition of running out of descriptors!

Perhaps it ought to be.
From: Christopher C. Stacy
Subject: Re: Destructors
Date: 
Message-ID: <uwusify5m.fsf@grant.org>
>>>>> On Sat, 29 Jun 2002 05:00:40 GMT, Joe Marshall ("Joe") writes:
 Joe> "Kaz Kylheku" <···@ashi.footprints.net> wrote in message ·················@luna.vcn.bc.ca...
 >> GC probably won't be triggered on the condition of running out of descriptors!
 Joe> Perhaps it ought to be.

In MACLISP, I have a vague recollection that the function 
named "GCTWA" (a version of the function "GC") did something
with cleaning up file descriptors (our OS called then "channels").
But I think they had to first be explicitly closed with CLOSE
(which was not enough to GC them...some kind of intermediate resource?).  
I guess I have forgotten exactly what that was all about.

Anyway, having control over the GC in various ways, such as 
setting up various kinds of triggers for it, is a good idea.
From: Kaz Kylheku
Subject: Re: Destructors
Date: 
Message-ID: <afkl5g$o3v$1@luna.vcn.bc.ca>
In article <······················@sccrnsc02>, Joe Marshall wrote:
> 
> "Kaz Kylheku" <···@ashi.footprints.net> wrote in message ·················@luna.vcn.bc.ca...
>>
>> GC probably won't be triggered on the
>> condition of running out of descriptors!
> 
> Perhaps it ought to be.

Then you need to filter all system calls which can create a descriptor.
From: Joe Marshall
Subject: Re: Destructors
Date: 
Message-ID: <iBnT8.360306$cQ3.23221@sccrnsc01>
"Kaz Kylheku" <···@ashi.footprints.net> wrote in message ·················@luna.vcn.bc.ca...
> In article <······················@sccrnsc02>, Joe Marshall wrote:
> >
> > "Kaz Kylheku" <···@ashi.footprints.net> wrote in message ·················@luna.vcn.bc.ca...
> >>
> >> GC probably won't be triggered on the
> >> condition of running out of descriptors!
> >
> > Perhaps it ought to be.
>
> Then you need to filter all system calls which can create a descriptor.

That doesn't strike me as too onerous.
From: Erik Naggum
Subject: Re: Destructors
Date: 
Message-ID: <3234315948769890@naggum.net>
* Kaz Kylheku
| You may run out of descriptors if you generate too many open file descriptors
| before the next garbage collection happens (GC probably won't be triggered on
| the condition of running out of descriptors!)

  This is actually an important point.  I had an application once that I tuned
  down to cons very little memory, but which opened and closed a lot of
  streams.  In Allegro CL at the time, streams allocated buffers from a pool of
  memory that was not garbage collected the same way other Lisp memory was
  (called the C heap -- I think the reason was that the buffers should stay put
  and not move around with their stop-and-copy garbage collector).  This memory
  could also not be released the same way a huge Lisp heap could be released
  once it had all turned into garbage.  My application had been running for
  about three months when I noticed that it had consumed lots of swap space.
  It had showed no signs of slowing down, either, bu the dataset was now some
  280M of C heap and 120M or so with Lisp heap.  By decreasing the garbage
  collection frequency, I had accidentally let the C heap grow *huge* before
  the Lisp heap triggered a garbage collection and almost all of it was freed.
  The Lisp heap was fairly stable -- most of the objects created during a day's
  run would remain in memory until the midnight cleanup -- so I had effectively
  turned off garbage collection during the day.  Tuning the garbage collection
  so it happened about every half hour during the working hours led to a 16M C
  heap and 70M Lisp heap -- because the objects were now in old space instead
  of the duplicated new space.  It was an important lesson in the mechanics of
  garbage collection, which turned out to be useful when I decided to live the
  same place for more than two years -- annual copying garbage collection had
  worked just fine during my university years.
-- 
  Guide to non-spammers: If you want to send me a business proposal, please be
  specific and do not put "business proposal" in the Subject header.  If it is
  urgent, do not use the word "urgent".  If you need an immediate answer, give
  me a reason, do not shout "for your immediate attention".  Thank you.
From: Kaz Kylheku
Subject: Re: Destructors
Date: 
Message-ID: <afkl5h$o3v$2@luna.vcn.bc.ca>
In article <············@luna.vcn.bc.ca>, Kaz Kylheku wrote:
> In article <···············@sindri.juniper.net>, Joel Ray Holveck wrote:
>>> I have the same question as Marcin...
>>> If an object is not referenced by anybody, how can I run a "destruction"
>>> code?
>>> It is necessary for releasing external resources..
>> 
>> Every time I see a question about finalization, I hear lots of
>> admonition about what it shouldn't be used for.  So, what would be an
>> appropriate use of finalization?
> 
> They are for just-in-case cleanup after sloppy programming. That is
> one explanation for their inclusion in the Java language.
> 
> What you can do with a finalizer is place an assertion in it which signals an
> error if it finds the object to be other than cleaned up. Kind of like a
> mortician checking for any signs of life before replacing the blood with
> formaldehyde. ;)

Actually here is one more potential use. Suppose that you have some
container data structure which holds on to objects, such as perhaps
a global list, which allows you to iterate over some collection of
related objects.  It would be nice to be able to say that ``this collection
only tentatively references these objects''. So that when no other part of the
program has a reference, a cleanup routine is executed which removes the object
from that collection.

In a part of a C++ program that I wrote long ago, there was a master object
which held on to a collection of reference-counted subordinate objects.  It
owned a reference to each one of them. When the reference count dropped to 1,
it would remove the object from its collection and then drop the reference one
more time. A periodic timer callback, or perhaps it was a dedicated thread,
would sweep over the collection from time to time and perform this action. So
that's a kind of finalization mechanism.

Finalization cannot exist without a special object state distinct from
``garbage''. Java calls it ``finalizable'', with a further complication that a
finalizable object may hold references to others, which are not finalizable
independently of it, and so are in the ``finalizer-reachable'' state.

The problem with built-in finalization is that it's useless for doing
the kind of thing I describe above unless there is a way to ``bless''
a reference as being tentative, weak or whatever you want to call it.
From: Erik Naggum
Subject: Re: Destructors
Date: 
Message-ID: <3234312306448848@naggum.net>
* Joel Ray Holveck
| Every time I see a question about finalization, I hear lots of admonition
| about what it shouldn't be used for.  So, what would be an appropriate use of
| finalization?

  In my somewhat limited experience, it is not useful without "weak pointers",
  which are objects the weak pointers to which "vanish" when they are the only
  pointers that keep it alive for purposes of garbage collection and the object
  is therefore not kept alive, either.  Sometimes, you would want a system that
  uses weak hashtables for cached results of some sort, meaning that until the
  garbage collector runs, you can reference an object through a weak pointer,
  but if you have had no use for it at the time garbage collection occurs, it
  will effectively be tossed.  This is a very useful feature, but if you want
  to make the most of it, you might want some concomitant information that
  should be alive only when the object itself is alive, but which you would not
  want to tie together with a lot of pointers all over the place, because that
  would defeat the purpose of weak pointers.  Instead of letting things point
  to the weak object, you let them reference them indirectly and then let the
  weak object know.  When the weak object is tossed, it will know how to remove
  any indirect traces of itself with it, that would either not vanish on their
  own at all or which would need a test for whether their target had vanished.
  (Weak pointers magically turn to nil after garbage collection.)

  This may be very abstract and sound rather weird, but for a more intuitive
  example, think of human memory.  Forgetting is a rather important feature of
  human memory, which is extremely underrated.  Forgetting the conclusions when
  the observations are invalidated takes conscious effort in most people.  You
  find lots of people who "learn" something, then integrate that knowledge with
  something else and come up with a conclusion of some sort, which they tend to
  believe even after the first thing they learned turned out to be all wrong.
  It would be much better if the first thing you learned had a normal pointer
  to it on its own and weak pointers to the conclusions that were based upon it
  (because they should seamlessly vanish if invalidated, too), so that if you
  dropped the normal pointer, the finalization would know how to invalidate the
  conclusions based upon it as it went.  A simpler example is perhaps that you
  worked out a difficult probability problem a decade ago and then you remember
  that you solved it, but not what the solution was.  I may not be an old man,
  in fact I'm pretty sure I'm not, but working through old math textbooks can
  be a very humbling experience, to be repeated once very decade or so so you
  at least still know that your brain works, but the kind of ridiculous despair
  you may feel the first time in remembering that you solved it and trying so
  much harder to remember it than to work it out again, is probably very close
  what a Common Lisp program feels when it goes looking for the cached result
  of a three-second long computation and the weak pointer only goes "no".  On
  the flip side of Alzheimer's, there are many ways to get screwed if you
  remember something for too long, too.  Many Lisp programmers experience that
  the system behaves differently after a cold start because they forgot that
  they have done something the system had not forgotten along with their memory
  of having done it.  Emacs (Lisp) users sometimes have this problem, a useful
  keybinding that isn't, a mouse wheel that beeps or scrolls the wrong window,
  forgetting the last keyboard macro you used and thinking you invoked the
  previous one.  Such stuff.  The best expression of this problem was provided
  by an acquaintance of mine when his X server crashed and all remote sessions
  died, his multiple Emacsen croaked, his log output windows closed, and he was
  facing the standard X root window, all grey.  "My context!", he said quietly.
  Not that finalizers would have helped him.

  When I restrict the usefulness of finalization to weak pointers, it is
  because I strongly favor explicit cleanup for normal objects.  However, there
  is a whole world out there who do not.  The C++ crowd, for instance, have a
  moderately useful feature in that the destructors of stack-allocated objects
  are called when the stack is, for lack of a precise term, unwound.  (It is
  not, of course, unwound the way Common Lisp does it.)  If something like this
  is needed in Common Lisp, a competent Common Lisp programmer would simply
  design a new binding form that effectively calls the finalizer when you leave
  scope unless the object has been passed out of the scope in, say, a returned
  value.  Such a programming style could, for instance, be used with resources,
  where a "resource" is an object of a type that is picked off a pool of weak
  pointers to previousely deallocated objects when you need one (or a fresh
  object is allocated) and effectively returned to the pool when you exit
  scope.  The "finalization" would be to return it to the pool, but you would
  not do that if you were returning it.  Figuring out such lifetime thingies is
  computer work.  A similar stunt _could_ be used when dealing with streams:
  Suppose you close all streams upon scope exit that you have not returned to
  your caller as open streams.  You would want that stream to be closed when
  the caller just dropped it sometime later.  Note that the file descriptor in
  Unix is a resource of the above-mentioned kind and that the operating system
  has a finalization routine that is invoked upon exiting the program.  You
  would want similar precautions in a well-honed Common Lisp program.  Leaks
  are bad, and finalization may be used to ensure that you find them, but in
  order for leak detection to really work, you want to keep track of things
  that might leak with weak pointers.

  Finally, note that implementationally, finalizers are easily implemented with
  weak pointers -- instead of just turning the weak pointer to nil when only
  weak pointers point to the object, you would call the finalizer first.
-- 
  Guide to non-spammers: If you want to send me a business proposal, please be
  specific and do not put "business proposal" in the Subject header.  If it is
  urgent, do not use the word "urgent".  If you need an immediate answer, give
  me a reason, do not shout "for your immediate attention".  Thank you.
From: Thomas F. Burdick
Subject: Re: Destructors
Date: 
Message-ID: <xcvbs9tooll.fsf@apocalypse.OCF.Berkeley.EDU>
Joel Ray Holveck <·····@juniper.net> writes:

> > I have the same question as Marcin...
> > If an object is not referenced by anybody, how can I run a "destruction"
> > code?
> > It is necessary for releasing external resources..
> 
> Every time I see a question about finalization, I hear lots of
> admonition about what it shouldn't be used for.  So, what would be an
> appropriate use of finalization?
> 
> I hear "external resources", but "not Unix FDs", which are possibly
> the most forgiving external resource I can think of.  So what would be
> an external resource for which finalization would be appropriate?

Only someone who's never had a server run out of FDs would think
they're forgiving :-).  It's okay if your application keeps a
predictably and constant sized pool of unused FDs around, but if it
leaks them in a way that the number of unused FDs increases with time,
long-running applications will get burned.

I can think of an instance when it would make sense to use finalizers
to close FDs, though.  Say you want to deal with data sets that can't
fit in your VM.  So you implement a class that's a proxy object that
you can use like an array (say), but which manages the retrieval of
the information from files itself.  To keep the illusion of these
objects being arrays, you don't want to have to call a destructor on
them by hand, because then your code needs to know which arrays are
arrays, and which are your proxy objects.  So you use finalization to
close the FDs the proxy object has open, possibly free memory in the C
heap, etc.  You can deal with the problem of keeping the number of FDs
bound, seperately: eg, keep a global pool of them for use by this
class, and allow them to steal them from one another, as needed.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: John Wiseman
Subject: Re: Destructors
Date: 
Message-ID: <m21yaoppl6.fsf@server.local.lemon>
Joel Ray Holveck <·····@juniper.net> writes:

> Every time I see a question about finalization, I hear lots of
> admonition about what it shouldn't be used for.  So, what would be
> an appropriate use of finalization?

I wrote some code that attempted to make it both easy and efficient to
do 3D graphics from lisp by interfacing to an existing retained mode
API.  "Retained mode" means that every time you want to draw a 3D
object on screen, instead of explicitly rendering every vertex and
surface and normal and texture (as in OpenGL), you pass it an object
you've previously built using the API that contains all those things.

I wanted it to be as easy and natural for people to use 3D objects
they'd created as it was to use standard lisp data types.  E.g.,
something like this to create a window displaying a rendered sphere:

  (make-instance 'q3:qd3d-window
    :view-model (q3:create-sphere 0 0 0 1))

Or to create a group consisting of copies of the same sphere, with one
red and the other blue and translated:

  (let ((s (q3:create-sphere 0 0 0 1)))
    (q3:create-display-group
      (q3:create-attribute-set :diffuse-color 1 0 0)
      s
      (q3:translate-transform (q3:create-transform) 5 0 0)
      (q3:create-attribute-set :diffuse-color 0 0 1)
      s))

In particular I wanted to shield users from the reference counting
scheme that the underlying API used to manage the memory used by all
these objects, so I used MCL's finalization facility (MCL calls it
termination).  It worked extremely well and freed users from having to
deal with the details of memory management that often annoyed (me, at
least) when writing code in C that used this API.

There was one hitch, similar to one which Erik Naggum describes
running into in one of his postings: The 3D objects were allocated
from a different heap than lisp objects, so I sometimes ran out of
space in the 3D heap because lisp hadn't felt the need to GC.  In
practice, this happened very rarely.  And later, once 64 MB RAM became
a typical amount of memory for a workstation, it never happened again
to me.

The other thing I did was to also offer macros for making explicit
management of 3D object lifetime easy.  So if someone wanted to write
code like the examples above, they could (which was especially great
for explorative programming), but if they wanted to they could make
optimal use of the 3D heap by instead writing

  (q3:with-q3-objects
      ((s (q3:create-sphere 0 0 0 1))
       (red (q3:create-attribute-set :diffuse-color 1 0 0))
       (blue (q3:create-attribute-set :diffuse-color 0 0 1))
       (xform (q3:translate-transform (q3:create-transform) 5 0 0)))
    (q3:create-display-group red s xform blue s))

The with-q3-objects macro used unwind-protect cleanup forms that both
deallocated the 3D objects and cancelled finalization on them.

So i guess one possible answer to your question is something like
"when you are trying to make foreign data with fine granularity as
easy to use as native lisp data."  I was extremely happy that I had a
finalization facility for this use, and it certainly didn't feel at
all sloppy.  It let me do 3D graphics in a way that felt very lispy.


John Wiseman

    
From: Chris Double
Subject: Re: Destructors
Date: 
Message-ID: <uvg8f5bgl.fsf@double.co.nz>
Marcin Tustin <·····@witch.cheese> writes:

>     Is there a way of defining object destructors in CLOS?  I'd like
> to have a "create and forget" way of dealing with sockets, and this
> would be just the thing.

The standard idiom in Lisp, Dylan and other similar languages is to
use 'with-*' style macros:

  (with-socket (s "www.somehost.com" 80)
        (do-something s))

Which would expand to:

  (let ((s (open-socket "www.somehost.com" 80)))
    (unwind-protect
        (do-something s)
      (close-socket s)))

Or something similar. There is also finalisation which some Lisp's
support. This enables a function to be called when the object is
garbage collected. This is not such a good idea for resources like
sockets, database handles, etc. This is because there is usually no
guarantee that finalisers are called or when they are called. So it
may be a long time before your resource is released.

The best way is to define your protocol of usage properly and use
macros and/or unwind-protect whenever you can.

Chris.
-- 
http://www.double.co.nz/cl
From: Kalle Olavi Niemitalo
Subject: macros shuffling declarations (was: Destructors)
Date: 
Message-ID: <871yb3gc7k.fsf_-_@Astalo.y2000.kon.iki.fi>
Chris Double <·····@double.co.nz> writes:

>   (with-socket (s "www.somehost.com" 80)
>         (do-something s))

Let's insert some declarations:

  (with-socket (s "www.somehost.com" 80)
     (declare (special s) (optimize safety))
     (do-something s))

> Which would expand to:
> 
>   (let ((s (open-socket "www.somehost.com" 80)))
>     (unwind-protect
>         (do-something s)
>       (close-socket s)))

Now the expansion might be:

  (let ((s (open-socket "www.somehost.com" 80)))
     (declare (special s) (optimize safety))
     (unwind-protect
         (do-something s)
       (close-socket s)))

In this case, the macro could insert all the declarations in the
same place; this seems simple to program.

Is there a more difficult situation where the macro must actually
parse the declarations and distribute them in various places?
If the macro finds a non-standard declaration it does not
recognize, is it appropriate to signal a warning?
From: Thomas F. Burdick
Subject: Re: macros shuffling declarations (was: Destructors)
Date: 
Message-ID: <xcv660ex4nu.fsf@blizzard.OCF.Berkeley.EDU>
Kalle Olavi Niemitalo <···@iki.fi> writes:

[ snip example of a macro that deals with declarations ]

> In this case, the macro could insert all the declarations in the
> same place; this seems simple to program.
> 
> Is there a more difficult situation where the macro must actually
> parse the declarations and distribute them in various places?

Yes, I've written a few macros that had to parse declarations.  It's
really not hard at all, though.

> If the macro finds a non-standard declaration it does not
> recognize, is it appropriate to signal a warning?

No.  Non-standard declarations are allowed.  Imagine the following situation:

  * (declaim (declaration date-modified))
  * (defun foo (x)
      (with-some-macro (foo bar baz x)
        (declare (date-modified "19 June 2002")
                 #+cmu (ext:optimize-interface safety))
        x))

  *** Error: Unknown declarations when parsing body of WITH-SOME-MACRO:
             DATA-MODIFIED EXT:OPTMIZE-INTERFACE

That's not cool at all...

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kalle Olavi Niemitalo
Subject: Re: macros shuffling declarations
Date: 
Message-ID: <87hejx6f8a.fsf_-_@Astalo.y2000.kon.iki.fi>
···@blizzard.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Yes, I've written a few macros that had to parse declarations.  It's
> really not hard at all, though.

Could you show a sample expansion?

>   *** Error: Unknown declarations when parsing body of WITH-SOME-MACRO:
>              DATA-MODIFIED EXT:OPTMIZE-INTERFACE
> 
> That's not cool at all...

Well, I proposed a "warning".
From: Thomas F. Burdick
Subject: Re: macros shuffling declarations
Date: 
Message-ID: <xcv8z58pfit.fsf@tornado.OCF.Berkeley.EDU>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> ···@blizzard.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Yes, I've written a few macros that had to parse declarations.  It's
> > really not hard at all, though.
> 
> Could you show a sample expansion?

Oh boy ... I've only had to do this a couple times, and I write a lot
of macros, so I'm having a hard time thinking of a simple example that
you can take out of context, but a silly skeletal form might be:

  (declaim (declaration author))

  (semantically-complicated-binding ((a b c) (foo))
    (declare (special b)
             (type (or fixnum null) a b c)
             (dynamic-extent a)
             (optimize (speed 3) (safety 0))
             (author "Thomas F. Burdick"))
    (progn
      (foo a b)
      (bar b c))
    (do-cleanup a)
    (more-cleanup a))

=>

  (let ()
    (declare (optimize (speed 3) (safety 0))
             (author "Thomas F. Burdick"))
    (let ((a (foo)))
      (declare (dynamic-extent a)
               (type (or fixnum null) a))
      (unwind-protect
          (let ((b (do-something-with a))
                (c (do-something-else-with a)))
            (declare (type (or fixnum null) b c)
                     (special b))
            (foo a b)
            (foo b c))
        (do-cleanup a)
        (more-cleanup b))))

> >   *** Error: Unknown declarations when parsing body of WITH-SOME-MACRO:
> >              DATA-MODIFIED EXT:OPTMIZE-INTERFACE
> > 
> > That's not cool at all...
> 
> Well, I proposed a "warning".

Okay.  But error or warning, I still think the macro should do
nothing.  Leave it to the underlying system to determine if the
declaration is known.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kalle Olavi Niemitalo
Subject: Re: macros shuffling declarations
Date: 
Message-ID: <87bsa3enad.fsf@Astalo.y2000.kon.iki.fi>
···@tornado.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

[when a macro does not recognize a declaration]
> Okay.  But error or warning, I still think the macro should do
> nothing.  Leave it to the underlying system to determine if the
> declaration is known.

The unrecognized declaration may refer to variables or functions.
Without knowing the syntax, the macro cannot know which they are
and how the declaration should be split if the expansion binds
them in different forms.  This would be important with an
EXT:NOT-SPECIAL declaration.

In my and your examples, macros move declarations around in order
to keep bound declarations bound (and free declarations free, but
that is easier).  Are there any other reasons for doing it?
From: Thomas F. Burdick
Subject: Re: macros shuffling declarations
Date: 
Message-ID: <xcvsn3fnojd.fsf@apocalypse.OCF.Berkeley.EDU>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> ···@tornado.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> [when a macro does not recognize a declaration]
> > Okay.  But error or warning, I still think the macro should do
> > nothing.  Leave it to the underlying system to determine if the
> > declaration is known.
> 
> The unrecognized declaration may refer to variables or functions.
> Without knowing the syntax, the macro cannot know which they are
> and how the declaration should be split if the expansion binds
> them in different forms.  This would be important with an
> EXT:NOT-SPECIAL declaration.

Yes, this is a potential problem.  The only solutions I can think of
are to document the deficiency, so that users know what will happen to
their non-standard declarations; or to provide a mechanism for
describing what to do with nonstandard declarations.  The latter is
what I've done for mine (indeed, it was the language extension
allowing for LEXICAL declarations on variables in the compiler I'm
working on, that prompted me to implement this interface).  My macros
(only one actually uses the facility at the moment, but if I need to
write any others that parse declarations, I plan to use it more :) do
something like this:

  (parse-declaration '(ext:my-dynamic-extent a b #'foo))
  => (a b #'foo) ; affected variables
  => nil         ; more information needed to reconstruct declaration
  (build-declaration 'ext:my-dynamic-extent nil 'a 'b 'c)
  => (ext:my-dynamic-extent a b c)
  (parse-declaration '(type (or fixnum nil) x y z))
  => (x y z)
  => (or fixnum nil)
  (build-declaration 'type '(or fixnum nil) x)
  => (type (or fixnum nil) x)

> In my and your examples, macros move declarations around in order
> to keep bound declarations bound (and free declarations free, but
> that is easier).  Are there any other reasons for doing it?

Not that I can think of.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kalle Olavi Niemitalo
Subject: Re: macros shuffling declarations
Date: 
Message-ID: <87r8izc72m.fsf@Astalo.y2000.kon.iki.fi>
···@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> (indeed, it was the language extension
> allowing for LEXICAL declarations on variables in the compiler I'm
> working on, that prompted me to implement this interface)

Out of curiosity, does a bound LEXICAL declaration in your Lisp
affect only the associated binding, or nested bindings as well?

  (declaim (special var))
  (let (var)
    (declare (lexical var))
    (let (var)))  ; <-- Is this VAR special again?  I'd expect so.

>   (parse-declaration '(ext:my-dynamic-extent a b #'foo))
>   => (a b #'foo) ; affected variables
>   => nil         ; more information needed to reconstruct declaration
>   (build-declaration 'ext:my-dynamic-extent nil 'a 'b 'c)
>   => (ext:my-dynamic-extent a b c)

Thank you for this example.  I was trying to design a functional
interface too, but with just one function that would both parse
the declarations and rebuild them to match a list of lists of
bindings.  Yours seems easier to use.
From: Thomas F. Burdick
Subject: Re: macros shuffling declarations
Date: 
Message-ID: <xcv660aq2e2.fsf@apocalypse.OCF.Berkeley.EDU>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> ···@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > (indeed, it was the language extension
> > allowing for LEXICAL declarations on variables in the compiler I'm
> > working on, that prompted me to implement this interface)
> 
> Out of curiosity, does a bound LEXICAL declaration in your Lisp
> affect only the associated binding, or nested bindings as well?
>
>   (declaim (special var))
>   (let (var)
>     (declare (lexical var))
>     (let (var)))  ; <-- Is this VAR special again?  I'd expect so.

It works just like special, so just the associated binding.  At
top-level, it's pervasive, too.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Thomas A. Russ
Subject: Re: macros shuffling declarations (was: Destructors)
Date: 
Message-ID: <ymir8j0uw0y.fsf@sevak.isi.edu>
···@blizzard.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> 
> Kalle Olavi Niemitalo <···@iki.fi> writes:
> 
> > If the macro finds a non-standard declaration it does not
> > recognize, is it appropriate to signal a warning?
> 
> No.  Non-standard declarations are allowed.  Imagine the following situation:

In fact, there is language support for telling the compiler about
such non-standard declarations, namely the DECLARATION declaration:

  Description:

  Advises the compiler that each name is a valid but potentially
  non-standard declaration name. The purpose of this is to tell one
  compiler not to issue warnings for declarations meant for another
  compiler or other program processor.

  Examples:

   (declaim (declaration author target-language target-machine))
   (declaim (target-language ada))
   (declaim (target-machine IBM-650))
   (defun strangep (x)
     (declare (author "Harry Tweeker"))
     (member x '(strange weird odd peculiar)))


In our Loom system we have used this to handle the use of some of the
newer ANSI declarations while not generating warnings in older CL
implementations as well.



-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
From: Thomas F. Burdick
Subject: Re: macros shuffling declarations (was: Destructors)
Date: 
Message-ID: <xcvn0tnnnzu.fsf@apocalypse.OCF.Berkeley.EDU>
···@sevak.isi.edu (Thomas A. Russ) writes:

> ···@blizzard.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > 
> > Kalle Olavi Niemitalo <···@iki.fi> writes:
> > 
> > > If the macro finds a non-standard declaration it does not
> > > recognize, is it appropriate to signal a warning?
> > 
> > No.  Non-standard declarations are allowed.  Imagine the following situation:
> 
> In fact, there is language support for telling the compiler about
> such non-standard declarations, namely the DECLARATION declaration:

No kidding.  You snipped that from my text:

  No.  Non-standard declarations are allowed.  Imagine the following situation:
  
    * (declaim (declaration date-modified))
  [...]

I'm assuming it was unintentional, but I don't appreciate being quoted
in such a way as to make it seem that I was ignorant of something
that's explained in the response.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Geoff Summerhayes
Subject: Re: Destructors
Date: 
Message-ID: <GB3Q8.37874$s82.3091321@news1.calgary.shaw.ca>
"Marcin Tustin" <·····@witch.cheese> wrote in message
·····················@vampire.i-did-not-set--mail-host-address--so-shoot-me...
>
>     Is there a way of defining object destructors in CLOS?
> I'd like to have a "create and forget" way of dealing with
> sockets, and this would be just the thing.
>

Why not write one without a destructor, and write a with-open-socket
macro (see: with-open-file) to handle the dirty work?

--
Geoff
From: Marcin Tustin
Subject: Re: Destructors
Date: 
Message-ID: <yztbvg88iw82.fsf@ghost.i-did-not-set--mail-host-address--so-shoot-me>
"Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> writes:

> "Marcin Tustin" <·····@witch.cheese> wrote in message

> >
> >     Is there a way of defining object destructors in CLOS?
> > I'd like to have a "create and forget" way of dealing with
> > sockets, and this would be just the thing.
> >
> 
> Why not write one without a destructor, and write a with-open-socket
> macro (see: with-open-file) to handle the dirty work?
> 
> --
> Geoff

    Thanks (And to everyone else who suggested this stuff) for the 
suggestion. Time to seriously up my level of CL knowledge again...

-- 
Mummy! Mummy! There's a twelve-foot stoat outside!