Re: long double versions of functions in gcc under Cygwin



ena8t8si@xxxxxxxxx wrote:
jaysome wrote:
On 8 Aug 2006 23:21:07 -0700, ena8t8si@xxxxxxxxx wrote:

Keith Thompson wrote:
ena8t8si@xxxxxxxxx writes:
Keith Thompson wrote:
In my humble opinion, most instances of goto statements point to a
missing feature in the language. In C, the major missing features are
named break (which could be used to break out of a specified loop
rather than the nearest enclosing one) and a decent exception
mechanism.
I don't agree with the basic premise, but for the
sake of discussion let's say I do. Do you really
think most gotos would be eliminated by C having
the features you named? In my experience most gotos
arise in one of three circumstances: bad coding,
branch to end of function to preserve single return
point, and machine generated C code (eg, YACC/LEX).
Breaking out of multiple loops seems like a distant
fourth (and usually remediable by putting the multiple
loops in their own function and using return); and
exception handling, it's hard to see how that's even
on the radar. It may be that C would benefit from
these features (personally I don't think it would,
but that's a separate issue), but even if it had
them it doesn't seem like goto usage would be affected
much.

My question above wasn't meant to be rhetorical;
I'm interested to hear your reactions.
Branching to the end of a function (for example because you need to
execute some cleanup code rather than doing an immediate return) is
something that's usually done in, ahem, *exceptional* circumstances.
I'm not sure that C++-style exceptions would be a good fit for C. As
I recall, any C++ object can be thrown as an exception. Ada's
exception mechanism might be worth considering. In the 1983 version
of the language, it's simpler than C++'s mechanism; an exception is
just an exception, and a handler can handle either named exception or
all exceptions. Of course, any such mechanism would have to be very
lightweight.

The idea is to work with named entities that relate to the problem
domain rather than jumping to a named point in the code.
The pattern I was talking about looks something like
the following:

int typfun()
{
int rc;
...
x = get_resource_one();
if(x==NULL){ rc = -1; goto BAIL1; }

y = get_resource_two();
if(y==NULL){ rc = -2; goto BAIL2; }

z = get_resource_three();
if(z=NULL){ rc = -3; goto BAIL3; }

rc = 0;
release_resource(z);

BAIL3:
release_resource(y);

BAIL2:
release_resource(x);

BAIL3:
return rc;
}

Obviously there are variations, and I've written
the if()'s on one line to save space, but I
think you get the idea.

A pattern like this doesn't map very well onto
try/catch blocks, or other exception handling
mechanisms.
This pattern maps very well onto try/catch blocks. First consider a
re-write of your example code (z=NULL corrected).

Yes thank you for the correction.
int typfun(void)
{
int rc;
...
x=y=z=NULL;
x = get_resource_one();
if(x==NULL){ rc = -1; goto CLEANUP; }
y = get_resource_two();
if(y==NULL){ rc = -2; goto CLEANUP; }
z = get_resource_three();
if(z==NULL){ rc = -3; goto CLEANUP; }

rc = 0;

CLEANUP:
release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

Now consider how it might be written in a language that provides
try/catch, and assumes release_resource() handles NULL, like it
should, like free() and delete and delete [] do:

int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try
{
x = get_resource_one();
if(x==NULL){ rc = -1; throw rc; }
y = get_resource_two();
if(y==NULL){ rc = -2; throw rc; }
z = get_resource_three();
if(z==NULL){ rc = -3; throw rc; }
}
catch(int i)
{
rc = i;
}

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

There's not much difference.

Two comments. First, not all resource allocation/release can be
rewritten in the style you suggest using release(NULL). [*]
Second, why would someone use throw when what's it's doing
basically just a goto in disguise?

Why use a for loop when it is just a while loop in disguise? Why use a while loop when it is just a conditional goto and an unconditional goto in disguise? Why use a do-while loop when it is just a conditional goto in disguise? Why use a break when it is just a goto in disguise?

> If the release(NULL) technique
works, it seems better to dispense with try/catch altogether:

int typfun()
{
int rc = 0;
...
x=y=z=NULL;
do {
x = get_resource_one();
if(x==NULL){ rc = -1; break; }
y = get_resource_two();
if(y==NULL){ rc = -2; break; }
z = get_resource_three();
if(z==NULL){ rc = -3; break; }
} while(0);

release_resource(x);
release_resource(y);
release_resource(z);
return rc;
}

Or, if one had try/catch
int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try {
x = get_resource_one();
if(x==NULL) throw -1;
y = get_resource_two();
if(y==NULL) throw -2;
z = get_resource_three();
if(z==NULL) throw -3;
}
catch( int i )
rc = i;

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

I'm sure it is a few characters less typing ;-)

[*] For performance reasons, among others.

Premature optimisation is the root of quite a lot of problems. Anyway, as someone else suggested you can always nest the blocks.

try/catch which propagates outside the function can be even more useful. Especially for library functions.

int mylibfunc(whatever)
{
/* do stuff */
if (condition)
/* This is a fundamental problem and it is not safe to continue
doing anything unless it is dealt with */
throw 1;
}

Unlike the return value if the caller ignores it then it propagates until the program exits with an error code or it is caught. I've done a lot of programming in a Pascal variant that had this and made a lot of use of it and it makes handling exceptional conditions a lot easier. Like most things it can also be abused ;-)
--
Flash Gordon
Still sigless on this computer.
.



Relevant Pages