Boost logo

Boost :

Subject: Re: [boost] expected/result/etc
From: Emil Dotchevski (emildotchevski_at_[hidden])
Date: 2016-02-13 00:36:50


On Fri, Feb 12, 2016 at 9:02 PM, Michael Marcin <mike.marcin_at_[hidden]>
wrote:

>
> Sorry I don't follow.
>>> Are you suggesting that the raytracer should be inlined into every call
>>> site?
>>>
>>>
>> I avoid using inline except if the profiler tells me it's needed. If it is
>> needed, then I inline regardless of whether the function emits exceptions
>> or not.
>>
>>
> Let me be more explicit.
>
> You certainly wouldn't inline a raytracer (a heavy operation) at every
> call site, you would just horribly bloat your executable for no benefit and
> likely achieve a degradation of performance.
>

Yes, so don't inline the whole thing, do pay the exception handling
overhead at the point when you call this high level function. The overhead
at this call point will be negligible, because as you say it's a heavy
operation. As you call deeper into the raytracer you will get to levels
where the exception handling and function call overhead will be
significant, and you'll inline those functions.

> However the premise is that the code can have errors in cases which are
> not unexpected (aka exceptional), which are not the result of programming
> errors (logic errors), which occur because of limits specifically put in
> place to constrain time and memory consumption of the operation
> (performance is important even in the error control flow).
>

Yes.

> What I think you're saying is that where I want to write code that looks
>>> like:
>>>
>>>
>>> result<int> bar()
>>> {
>>> return std::make_error_code( std::errc::bad_address );
>>> }
>>>
>>> int main()
>>> {
>>> int foo;
>>>
>>> auto _foo = bar();
>>> if ( _foo ) {
>>> foo = _foo.get();
>>> } else {
>>> foo = 0;
>>> }
>>>
>>> return foo;
>>> }
>>>
>>>
>>> I should instead write code that looks like:
>>>
>>> int bar()
>>> {
>>> throw std::system_error(
>>> std::make_error_code( std::errc::bad_address ) );
>>> }
>>>
>>> int main()
>>> {
>>> int foo;
>>>
>>> try {
>>> foo = bar();
>>> }
>>> catch ( std::system_error& e )
>>> {
>>> foo = 0;
>>> }
>>>
>>> return foo;
>>> }
>>>
>>>
>>> And I should expect equal performance?
>>>
>>>
>> Obviously not, because you're always throwing. Throw may incur overhead,
>> certainly does on Windows. What I'm saying is that when you don't actually
>> throw, exception handling overhead occurs exactly where function call
>> overhead occurs, and can be eliminated completely by inlining.
>>
>
> I thought it was obvious that that code is trying to illustrate a
> difference in interface. Obviously bar() is meant to do work that returns
> an int but sometimes can't and results in an error.
>
> If you're going to choose exceptions to report your errors you're not
> going to be able to avoid actually throwing because errors *will* occur (as
> that is the whole premise of this thread).

Let's say in your example, the function throws 50% of the times you call
it. Assuming this isn't an anomaly, it means that you're not really
throwing to indicate a failure, but to report a result. Obviously that's
not a good design.

If your function throws to indicate a failure, then the error path will
have some overhead, but the normal execution will have zero overhead, as
long as the function is inlined.

Emil


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