Boost logo

Boost :

Subject: Re: [boost] [system][filesystemv3] Questionabout error_codearguments
From: Domagoj Saric (dsaritz_at_[hidden])
Date: 2009-11-07 12:06:39


"Stewart, Robert" <Robert.Stewart_at_[hidden]> wrote in message
news:DF2E67F3D097004694C8428C70A3FD69046F55F92D_at_msgbal516.ds.susq.com...
>However, miscoded
>applications do get into production and it's awfully nice to get
>information about the real error -- not the, "Hey, stupid! You
>forgot to check for errors here" error -- to help diagnose the
>production problem.

true...it was never my intention/part of my original idea to throw such "hey,
stupid" errors as i explained and try to correct the ambigous wording of my
first post in the "way too long" post ;)

>> - the debugger can be instructed to break at points of smart_error<>
>> construction when the status_code with which it is
>> constructed is different from some "error_success" value...
>
> Yes, though of course conditional breakpoints are horribly slow in many
> debuggers.

true unfortunately...

>> _CrtDbgBreak when constructed with a non-success "actual_error" (when
>> debugging)...
>
> That's usually part of asserting on Windows as I recall.

yes, it was just an idea as it is perhaps easier to continue with execution
after a plain _CrtDbgBreak() than after a "full" assert...

>> > the overhead of checking to see whether to throw at each call site,
>>
>> there are ways that this can be minimized (or in some cases
>> eliminated):
>> - move the exception object construction and the throw
>> statement into a
>> separate (preferably nontemplated) function marked as noninline
>
> The conditional logic is not affected by that, which I already assumed when I
> made the statement you quoted.

the conditional logic itself is not, but the code as a whole is (it is
smaller/less bloated...with all other consequences that entails...)

>> - now we are left with an { if (!inspected && !succeded)
>> do_throw() } which
>> would/could probably translate to 5-6 cisc instructions
>
> That is more than zero instructions, even if your estimate is accurate.
> Besides, those instructions are conditionals which, if they are
> not guessed properly, will stall a highly pipelined CPU's instruction cache.

by all means...i never ment to claim it was 'practically zero' (you will
usually rather see me complain about even a single instruction more...or even
just a more complicated instruction...as in the [optional] layout thread...your
"typical garden variety premature optimizer" :) ...
...i was mearly exploring the possible options and solutions...'thinking
outloud'...if we cannot find a perfect/satisfying solution on the first try it
does not mean that we should not try at all/that such a solution does not
actually exist ;)
and yes it seems all the hours spent with the disassembly window opened paid
off :) ...the estimate was correct (if BOOLs, i.e. register sized integers, are
used instead of bools, yes our "favourite" architecture thinks small bools are
"evil") msvc++ 9 produces the following code:
00401C99 cmp dword ptr [esp],0
00401C9D jne $LN8 (401CABh)
00401C9F cmp dword ptr [esp+4],0
00401CA4 jne $LN8 (401CABh)
00401CA6 call do_throw (401C10h)

this can now probably be further reduced to three instructions/a single test if
the is_inspected bool is merged into a single free bit of the error_code (this
would most probably hurt the immediately-inspected case as it would no longer
be that transparent to the compiler but would benefit the use cases that use
exceptions...things like this can anyhow be left as a matter of global and/or
local configuration)...

>> - if the returned error object is imediately inspected after
>> the function
>> returns (as is the intended use) it is 'plain obvious' to the
>> compiler that
>> those "remaining instructions" are redundant and would be
>> removed completely...
>
> What appears obvious to a human is not always so to an optimizer. You must
> prove that assertion by testing.

i did of course...it's true (for msvc++ 9.0) ;)

> [snip more optimization thoughts]

yes...well...the issue is obviously not trivial...i was trying to 'prove' that
the issue (of more complex callers/call sites) is not immediate show
stopper...because on one hand it can be minimized to a certain extent or
completely removed in some cases while OTOH it is in fact not actually all that
clear what/which solution is actually more complex/less efficient in real world
usage scenarios...
...for example, in many situations removing throwing code from a function,
using the smart error code approach, removes possibly order of magnitude more
code from the function in question than it possibly adds to callling functions
that need to have eh code anyway (if they let returned smart error code objects
to auto convert to exceptions)...so in situations like these, unless there are
many different call sites (that use the exception approach) for such a
smart-error-code-returning function the actual outcome can turn out to be
beneficial even for those scenarios...

anyways, as said above, it seems to me that this particular issue is not an
apriori show stopper and further time should be wasted on it only when (or if,
as the discussion/further interest seems to be dead/dwindling) other issues and
'wrinkles' are polished...

>> > and the danger of throwing in the destructor during stack unwinding,
>>
>> we seem to be "running in circles"...(afaik) there is no such
>> danger for temporary objects...
>
> Of course there is:
>
> error_code error;
> f(error);
> do_something_that_might_throw();
> if (error)
> {
> deal_with_error();
> }

umm...that was not my proposal (that looks sort of like a mixture of the
boost::error_code approach and my proposal)...for one thing 'my smarter error
codes' are not be default constructible or reusable but meant to be simply
'returned' (and also not converted to a local scoped object...this is an issues
that still needs to be resolved)...

> If do_something_that_might_throw() throws an exception,
> error will not have been checked for errors. ~error_code()
> might detect an uncaught exception and avoid rethrowing,
> but there are other scenarios that complicate that.

it seems to me that all so far mentioned scenarios regarding the issue of
throwing in the destructor have been 'resolved' (including the gotw-047
issue)...

> Each function that might throw or use error_codes to report errors
> can use the proposed interface (Beman's original query) or can be
> overloaded. Given the complexity of what has been suggested for
> error_code to complain should its error state not be inspected and
> the variability of its making that complaint, means that simply
> overloading each such function is trivial by comparison. The
> semantics of overloading are well understood; nothing new need
> be invented.

well virtual functions were also a "new invention" at one point yet it was
still decided that a new standardized idiom was better than everyone
reinventing the wheel all the time with manual function pointer mechanics...
the same here...even if the "smart error code" approach is or seems "new"
and/or complicated (i will leave it at that for this point, as the issue was
already discussed elsewhere in the thread and in my 'too big' post) it does not
necessarly mean that it is flawed or bad just because of it...
...instead of asking or hoping that your "favourite library" writer/maintainer
will actually go through all the trouble of doubling his/hers public interface
we can solve the problem only _once_ per library or actually/probably per
language (if not per "universe")...by providing a standardized mean for library
writers not to even worry about the error reporting/handling mechanism and at
the same time for users to have full control over error handling...that is
"safe"/"by the book" out of the box..yet, when and if one wants/needs it,
configurable/"powerful" possibly less verbose and more efficient (and more
small-utility-that-would-rather-not-link-to-the-full-crt friendly) than a
default/"blind" "always use exceptions" approach...

and "last but not least" sometimes the notion of "complexity" is also "in the
eye of the beholder" (e.g. what some might regard as "complex" i might regard
as "configurable" or "powerfull")...

-- 
 "That men do not learn very much from the lessons of history is the most
important of all the lessons of history."
 Aldous Huxley 

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