Boost logo

Boost :

From: Stewart, Robert (stewart_at_[hidden])
Date: 2002-03-21 14:14:22


From: Brey, Edward D [mailto:EdwardDBrey_at_[hidden]]
>
> > From: Stewart, Robert [mailto:stewart_at_[hidden]]
>
> There's yet another approach, more like what I use in
> practice for scripting
> on internal projects:
>
> try
> {
> create script
> run program B
> remove(script)
> }
> catch (exception)
> {
> dump rich exception information
> }
>
> This simple catch-all approach has proven more than adequate for me in
> writing Python scripts, and it comes with the important
> benefit that I don't
> need to write all sorts of error handling or detection in the
> scripts. It
> is one of the reasons that Python is such a productive tool
> for scripting.

If you follow the lead of std::exception, then all you'll get is a string
(what()), not "rich exception information." That is the likely approach for
the exceptions thrown by remove(), so this approach won't work.

> However, I see one big obstacle that could prevent C++ from
> easily being
> equally useful (from an error handling point of view anyway):
> C++ doesn't
> provide a call stack dump. One reason that a catch-all is so
> useful in
> Python is that the stack dump shows you the context of the
> exception info.
> Without it, I suppose that more selective handling might be
> required to
> provide good diagnostics, depending on the complexity of the program.
> Alternatively, the program would need to record checkpoints
> to provide the
> context.

I can't see remove() doing that, especially if it is standardized.

> Agreed. My point is indicate that just as avoidable
> try-catch blocks are
> problematic, so are avoidable return-value checks. Each is
> inefficient
> (although exceptions more so) and requires more code.

My stated and, I think, justifiable for most "scripting" uses assumption is
that the caller nearly always doesn't care if the file doesn't exist when
calling remove(). The goal of this library is stated to make using C++ a
reasonably easy replacement for writing shell scripts, etc. For those
purposes, remove() should not throw an exception when the file doesn't
exist.

> > > Presume that you are making a utility to wipe files. You
> >
> > If you cannot delete the file, that's a problem. If the file
> > doesn't exist,
> > there's no problem. Before you ever got to the remove()
> > call, you would
> > have overwritten the file "many times." The code that
> > overwrites the file
> > will have error handling code to notice that the file
> > disappeared while
> > trying to overwrite it. Provided that code successfully
> > overwrote the file
> > the requisite number of times, it doesn't matter if the file
> > is gone by the
> > time remove() is called. The user doesn't need to know about that
> > condition.
>
> This is true in a perfect world. However, clearly, if the
> file disappeared
> unexpectedly, something has gone wrong. If the point of the

I don't find that to be "clearly" the case. See below.

> operation was
> to destroy sensitive data, it is reasonable to expect that

I don't find that "reasonable." See below.

> someone would
> want to know that there is something fishy going on.

If the file was fully overwritten, as I said, I don't see why the user cares
that something else deleted the file before remove() could. We're talking a
filesystem here, with many processes working in parallel to access the
files, so it wouldn't be unfathomable that this scenario could play out. If
the file were deleted while trying to overwrite it, then that's a big deal
that should be reported to the user.

> > If the user types a command that triggers a call to remove(),
> > then yes, the
> > program will want to notify the user that the file was
> > already gone. If the
> > user selects a file in a GUI display of the filesystem and
> > asks to delete
> > it, and by the time the GUI reacts to the UI events and makes
> > the call to
> > remove() the file is gone, then no, I don't think you'd want
> > to notify the
> > user. Since the file was visible in the GUI, then the UI
> and the user
> > thought it existed. When the "delete" operation is complete,
> > if the file is
> > no longer in the filesystem, then the operation was
> > successful, regardless
> > of whether the call to remove() actually removed the file or not.
>
> It's interesting that the implementation of the shell of the
> world's best
> selling operating system doesn't happen to follow this
> philosophy. So I'm
> not alone in disagreeing with you.

Are you sure? Did the file still exist in the GUI such that you could
delete it from the UI after deleting the file from a shell or other context?
Perhaps you couldn't replicate the scenario I outlined. Even if you could,
that doesn't invalidate my assertion; it could mean that you're in good
company in thinking that the wrong thing should happen. :P Seriously,
presuming you're alluding to Microsoft, they have never been known for being
the world's greatest UI designers, so their doing what I suggested shouldn't
be done doesn't sway my opinion.

> > I still see no compelling example requiring that remove()
> > throw an exception
> > if the file does not exist. The few examples that need to
> > know that the
> > file didn't exist when remove() tried to remove it can simply
> > check the
> > return value. If it isn't important to the application to
> > know about that
> > condition, then the application can ignore remove()'s return
> > value safely.
> > Simple.
>
> But not quite a simple as the linear approach, which is that
> a function does
> what it says it does or it throws an exception. One key

But we disagree as to what it does. I contend that it ensures the file
doesn't exist. You contend that it must actually remove the specified file.
Both can satisfy the "does what it says it does or it throws an exception"
description.

> motivation is to
> avoid a special case that is inconsistent with other IO
> functions. For the
> other functions, it isn't just the end (postcondition) that
> matters, it is
> also the means. If you move a file from src to dest, and the
> happens to
> already be at the dest and no the src, does move silently
> succeed? No. But

No. That would be destructive and clearly not benign; it is the antithesis
of the situation with remove().

> if you use remove() to logically do the same thing (only
> consider the dest
> as /dev/null), should we make a special case? I'd rather not.

It's a special case in terms of returning a value, but the condition under
discussion isn't a failure, so you don't need an exception!

> Of course, just because there are applications where a
> throwing remove() is
> desirable and just because we want to avoid special cases,
> doesn't mean that
> we should ignore the opportunity to simplify code that does
> want to ignore a
> failed remove. While it is easy to overestimate the fraction
> of cases where
> ignoring the problem is truly the best answer, I suspect that
> there are
> easily enough to justify making these situations easy to
> code. I see a

I write a lot of Unix shell scripts. Many of them call rm to remove a file
or directory. When I call rm to remove a file, I have *never* checked to
see whether the file was truly removed. I have, in some cases redirected
stderr to /dev/null to ignore error messages, and in other cases tested for
the file's existence before calling rm. The effect is largely the same,
particularly when nothing else is likely to be manipulating the files in
question.

My point is that were I to rewrite these scripts in C++, I'd always choose
to ignore the condition in which the file doesn't exist when calling
remove(). That is why this is important to me.

> couple of opportunities. One is to notice how opening a file
> has to deal
> with a similar issue: fail or truncate on existing file? The
> other is to
> provide a error handling context. I think that we can easily
> come to a
> solution that makes the library easy to use for just about any kind of
> application.

One of the things you're advocating here is two versions of remove(): one
that always throws exceptions and one that returns a value to indicate that
the file was removed or didn't exist. Overloading for those two approaches
is overkill. I don't mind if one remove() took a parameter to indicate
whether I want an exception for that condition, but I don't want to see two
functions.

It seems that I'm not convincing you nor are you convincing me about the
return value versus exception issue. We've aired our concerns, and since
Beman is writing the library, he'll have to make the final decision.

Rob
Susquehanna International Group, LLP
http://www.sig.com


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk