E
ena8t8si
Keith said:Sure. (The last label should be BAIL1, not BAIL3).
Yes, thank you for the correction.
Just off the top of my head ...
With exception handlers, that would probably be written as three
nested blocks rather than straight-line code with gotos. As long as
you're creating nested blocks, I suppose you might as well just use
if-then-elses.
The code could be a bit simpler if you could assume that
release_resource() does nothing with a null pointer, as free() does.
Something that just occurred to me is that exceptions (in Ada or C++)
propagate across function calls. If we're (hypothetically) doing this
just to handle control flow within functions, that's not necessary.
Perhaps one answer is, rather than exception handling, to allow a
named break to exit from any scope, not just a loop or switch
statement.
So maybe something like this:
int typfun() /* This is not C. */
{
int rc;
...
USE_RESOURCE_ONE:
{
x = get_resource_one();
if(x==NULL){ rc = -1; break USE_RESOURCE_ONE };
USE_RESOURCE_TWO:
{
y = get_resource_two();
if(y==NULL){ rc = -2; break USE_RESOURCE_TWO; }
USE_RESOURCE_THREE:
{
z = get_resource_three();
if(z=NULL){ rc = -3; break USE_RESOURCE_THREE; }
rc = 0;
release_resource(z);
}
release_resource(y);
}
release_resource(x);
}
return rc;
}
The goto version is shorter, has the same number of labels,
and doesn't exhibit the crawling indentation property.
This version doesn't seem like an improvement to me.
Or, if release_resource() works correctly with a null pointer argument:
int typfun() /* This is not C. */
{
int rc;
...
USE_RESOURCES:
{
x = get_resource_one();
if(x==NULL){ rc = -1; break USE_RESOURCES; }
y = get_resource_two();
if(y==NULL){ rc = -2; break USE_RESOURCES; }
z = get_resource_three();
if(z=NULL){ rc = -3; break USE_RESOURCES; }
rc = 0;
} /* end of USE_RESOURCES block */
release_resource(z);
release_resource(y);
release_resource(x);
return rc;
}
Since there is only one level of nesting, this
structure can be achieved using a do/while(0)
block:
int typfun() /* C, not counting some missing declarations. */
{
int rc;
...
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; }
rc = 0;
} while(0);
release_resource(z);
release_resource(y);
release_resource(x);
return rc;
}
So under the assumption that release(NULL) works,
the gotos in the original I would put under the
"bad coding" category more than needing a new
language control structure.
Maybe there are better motivating examples;
I just don't know what they are.