Subject: Re: testing for open-ness (was Re: conservative gc sucks) From: Erik Naggum <firstname.lastname@example.org> Date: 11 Jan 2003 03:57:25 +0000 Newsgroups: comp.lang.lisp Message-ID: <email@example.com> * firstname.lastname@example.org (Tom Lord) | Consider the example I posted a while back: a computation that | involves a graph whose nodes may refer to streams which are network | connections. When part of the graph become inaccessible, _that_ is | when the stream needs to be closed. In that example, it is my | program, not the stream peer, who marks the end-of-stream. My | program has to make that decision based on the lifetimes of nodes in | my graph. The garbage collector is already there, computing those | lifetimes for me -- it is the right tool for the job. Tom, which war are you fighting? I am trying to show you that the way you see things has contributed to, if not produced, conclusions that you stick by as if they were The Exclusive Truth, which they are not, and that if you opened up a little bit, you would find that you can look at the same evidence in different ways and arrive at very different conclusions. If you have a problem, we will help you find a solution. But there is, I suspect, a desire on your part to prove your initial hunch, and to do this you construct ever more problems when your "challenges" have been solved, but to anyone who listens to such "argumentation", the conclusion is fairly inevitable: You construct more "problems" in order to support a foregone conclusion. But here's how to implement garbage collection of file descriptors: Scan the heap for streams and look into them for file descriptors. When you have collected all the file descriptors this way, and maybe accounted for system streams, loop over the file descriptor space and close all that are not supposed to be open. It would not hurt if you did this after a garbage collection, of course, but it can be done at any time with no ill effects (other than a slew of system calls that result in harmless error returns). Please note that I said "garbage collection of file descriptors" and not "garbage collection of streams". This difference is important only because you have to be slightly more careful about caches and buffers. In a programming style that depended on this scheme, you would naturally want to force writing buffers to disk before you dropped the stream. This means that "but it would not work, because I want garbage collection to flush the stream buffers" is not a very smart counter-argument. You would make it only to strongly affirm my conjecture that you are making up problems as you go in order to defend your desire for a change in design. | That's a wrong solution because closing and opening a file may | return you different file from the one you started with. The | solution you've proposed changes the semantics of the program. Tom, listen. You do this trick when it /preserves/ the semantics of the program. You really do understand this and only pretend to be stupid, don't you? If the file referenced by a filename changes from open to open, you are not really working with /files/, which you said you were, so this is specious at best. It really looks as if you are making up problems, now. | There is a kind of reductio against my argument if you think I meant | to say "strictly not impelementable". One could write a graph | tracer in lisp itself and, at the application level, garbage collect | for streams. So if you think I said "strictly not impelementable", | that reductio should give you a clue that you've misread me ;-) All very good, but do you pick up clues that you have misread others? The above, for instance, is just plain silly. We all know that with sufficient work, everything is strictly implementable in any language. So I do not think you meant to say anything. Unlike you, I do not entertain specious arguments for their own sake, so it is quite foreign to me that you you have to defend yourself against something you think I think you meant to say. Really. So, please, clean up this mess and try to write better if you have such fears. I believe, but not very strongly, that the reason for your failure to be happy with the language as it is, is that you brought with you a model of perfect language design before you came to Common Lisp and now you think Common Lisp ought to conform to it. I think the reason that I tend to learn quickly and "side" with authorities, is that most of the time, I attach no personal identity to the models I bring with me when I am relatively ignorant. When I occasionally do (and the first example that comes to mind is Perl), I also fail at learning it. Back in 1993/4, I worked with C++, and the whole experience was exceedingly painful because the desire to redesign and fix the language was so strong that I had to fight it all the time to get any work done. Every now and then, I see people who come to various newsgroups with a "question" that is really a scream of despair that reality is not what they wanted it to be. I used to have a .signature line that I took from SF Gate columnist Mark Morford (which he may well have taken from somewhere else and that joke was lost on me), which pissed off a lot more people than I sort of intend my .signature to do, reading "if this is not what you expected, please alter your expectations", but I think it is actually a really good epitaph to life in general. The question is not whether Common Lisp (qua language) guarantees garbage collection to close streams cleanly, the questions are what you would do differently if it did and whether you can do the same things even if it does not. I realize that this is more problem- solution-oriented than many people appear to appreciate, but some times, the only available solution is not as stunningly beautiful as you had dreamt of, because it has to make space for something more. So, since Common Lisp does not guarantee orderly closure of streams when the stream object is garbage collected, /but/ implementations tend to offer finalization because it is sometimes exceedingly nice to have a safety net, /and/ the mechanism is non-portable, so you need to build some sort of abstraction on top of it, anyway, you might as well implement something even cleaner on top of it all. When you do this, there is very little danger that you will need to worry about how the system cleans up after you, because you will do it yourself. I have suggested two ways to do this that work very well for their inherently limited set of circumstances, and you should be able to think of some more of your own if you can only come to peace with the fact that you have to do /something/ on your own to get the behavior you desire. -- Erik Naggum, Oslo, Norway Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.