I'm mostly interested in C. Nevertheless, you can of course also do
the same in C:

struct option_float
{
    float value;
    int error_code;
    bool succeeded;
};

struct option_float inverse(int x) {
  if (x == 0)
    return (struct option_float){ .succeeded = false, .error_code = EDOM };
  return (struct option_float){ .value = 1.0f / x, .succeeded = true };
}

you get the idea. The difference is that it's hard to optimize the
non-error execution path if the compiler is not aware of the
semantics. Also, with exceptions, this can happen:

    float inverse(int x)
    {
        if (x == 0)
            throw overflow;
        return 1.0f / x;
    }

    y = inverse(x);

Which means control is taken from the function calling inverse without
it explicitly allowing it, which is not in the spirit of C.

P.S. programming in a lot of languages is _mere syntax_ with respect
to some others. Still, some syntaxes are good and some not. If we can
improve GNU C's syntax to be shorter, but without loss of
expressiveness or clarity, then why not!

On Mon, Mar 10, 2014 at 6:18 PM, Andrew Haley <a...@redhat.com> wrote:
> On 03/10/2014 03:09 PM, Shahbaz Youssefi wrote:
>> Regarding C++ exceptions: exceptions are not really nice. They can
>> just make your function return without you even knowing it (forgetting
>> a `try/catch` or not knowing it may be needed, which is C++'s fault
>> and probably could have been done better). Also, they require
>> complicated operations. You can read a small complaint about it here:
>> http://stackoverflow.com/a/1746368/912144 and I'm sure there are many
>> others on the internet.
>
> A few quibbles here.
>
> Firstly, C++ exceptions do not require complicated operations: an
> implementation may well do complicated things, but that's not the
> same at all.  In GCC we use DWARF exception handling, which is
> designed to be near-zero-cost for exceptions that are not thrown,
> but is more expensive when they are.
>
> There is no inherent reason why
>
>     float inverse(int x)
>     {
>         if (x == 0)
>             fail;
>         return 1.0f / x;
>     }
>
>     y = inverse(x) !! goto exit_inverse_failed;
>
> should not generate the same code as
>
>     float inverse(int x)
>     {
>         if (x == 0)
>             throw overflow;
>         return 1.0f / x;
>     }
>
>     try {
>         y = inverse(x);
>     } catch (IntegerOverflow e) {
>         goto exit_inverse_failed;
>     }
>
> This assumes, of course, a knowledgeable optimizing compiler.
>
> Also, consider that C++ can already do almost what you want.
> Here we have a function that returns a float wrapped with a
> status:
>
> option<float> inverse(float x) {
>   if (x == 0)
>     return option<float>();  // No value...
>   return 1.0f / x;
> }
>
> float poo(float x) {
>   option<float> res = inverse(x);
>   if (res.none())
>     return 0;
>   return res;
> }
>
> GCC generates, quite nicely:
>
> poo(float):
>         xorps   %xmm1, %xmm1
>         ucomiss %xmm1, %xmm0
>         jp      .L12
>         jne     .L12
>         movaps  %xmm1, %xmm0
>         ret
> .L12:
>         movss   .LC1(%rip), %xmm1
>         divss   %xmm0, %xmm1
>         movaps  %xmm1, %xmm0
>         ret
>
> The difference between
>
>     y = inverse(x) !! goto exit_inverse_failed;
>
> and
>
>   option<float> y = inverse(x);
>   if (y.none())
>     goto exit_inverse_failed;
>
> is, I suggest to you, mere syntax.  The latter is more explicit.
>
> Andrew.
>

Reply via email to