You know, not every function releases all the resources it claims before it returns. Sometimes acquiring those resources is exactly the reason why you called said function. Think of the initializer (or insertion into) of almost any kind of container data structure, for example.
C++ has FAR too many evil temptations in it to be allowed in many situations: the sword itself incites to violence. C is far simpler and easy to understand what is happening.
Here's an alternate form that uses goto's: {
if (-1 != (dest = creat("file.txt", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))) {
perror("Unable to create file.txt");
goto FAIL;
}
if (-1 != (src = open("source.txt"))) {
perror("Unable to open source.txt");
goto FAIL_DEST;
}
if (-1 != (rd = read(src, buf, 1024))) {/* should reading zero bytes be an error? */
perror("Read failed");
goto FAIL_BUF;
}
for (total_written = 0; total_written < rd; total_written += wr, buf_p += wr) {
if (-1 == (wr = write(dest, buf_p, rd-total_written))) {/* TODO check errno for fixable errors like EAGAIN or EINTR */
perror("Error writing to file");
goto FAIL_BUF;
}
}
FAIL_BUF:
free(buf);
FAIL_SRC:
close(src);
FAIL_DEST:
close(dest);
FAIL: }
I prefer this form because the main line execution is significantly clearer (i.e. - you don't have ever deeper nesting of the successful path), especially if you have even more resources to acquire that can fail. Also, errors are handled immediately (e.g. - the associated perror() is right there where the error is detected rather than potentially hundreds of lines below) and the main line of execution is obviously aborted and cast off to error handling / cleanup code.
An even better example would be an initializer function that only releases the acquired resources on error and on success leaves them acquired when it returns. There, the if-else structure you used won't work -- or your successful return is buried deep inside your nested successful if's with a different exit point for errors.
Why make two functions when one suffices? Especially when you already have goto error handling that naturally gives you a good spot for a single exit point anyway (as all your error exits will go out the same way)?
"A label for each potential failing resource?" Yes.
"An unwound set of labels?" You reclaim the resources in the reverse order that you acquired them so that the error handling code is common to all the error goto's. Basically an explicit form of C++'s stack unwinding and deconstructor invocation.
"What convention are you using for the labels?" I typically name the labels as FAIL_${last_successfully_acquired_resource_name}. For example, "goto FAIL_LOCK;" for a failure that occurs after acquiring a mutex named "lock".
I keep seeing people talking about using setjmp / longjmp to handle errors and cleanup, but I'm not familiar with that style and don't see how it solves the problem.
With goto's you jump to exactly the cleanup code you need to release the resources that you have already acquired within the function -- usually in reverse order so that you are effectively doing what C++ block destructors would do automatically for you.
setjmp / longjmp would let you return to a previous point in your code but wouldn't do anything for the actual necessary cleanup unless everything was on the stack right?
Write an example that properly handles 5 different mallocs within the same function and properly cleans up after itself on failure without using goto's. Here's the goto example:
if (NULL == (ret = malloc(sizeof(Resources))))
goto FAIL;
if (NULL == (ret->rsrc1 = malloc(sizeof(ret->rsrc1))))
goto FAIL_RESOURCES;
if (NULL == (ret->rsrc2 = malloc(sizeof(ret->rsrc2))))
goto FAIL_RSRC1;
if (NULL == (ret->rsrc3 = malloc(sizeof(ret->rsrc3))))
goto FAIL_RSRC2;
if (NULL == (ret->rsrc4 = malloc(sizeof(ret->rsrc4))))
goto FAIL_RSRC3;
assert(ret);
goto END;
/* error handling and return */
FAIL_RSRC3:
free(ret->rsrc3);
FAIL_RSRC2:
free(ret->rsrc2);
FAIL_RSRC1:
free(ret->rsrc1);
FAIL_RESOURCES:
free(ret);
ret = NULL;
FAIL:
assert(!ret);
END:
return ret; }
Also, it isn't always the case that the thing you need to reclaim is a pointer and can be dynamically tested as to whether it was successfully acquired or not. For example, you can't test a pthread_mutex_t to see if it is valid or not. Your code has to know either based on its structure (i.e. - like the above) or you have to have a separate tracking variable per such object.
PS - Yes, the example is a bit contrived, there'd be little reason to malloc those members rather than just have them allocated as part of the Resources struct. I just did that as an illustrative example. Also, I'd typically cast the result of a malloc to the appropriate type so that a C++ compiler wouldn't complain about my code, but I haven't specified their types in this example.
Your code is actually an example of why you should use goto rather than another construct.
I notice that you left the/* Do Cleanup */ part unimplemented. Now why didn't you fill that bit in if it's so easy? I'll tell you why: all your error breakouts jump to the same spot and so your cleanup code has to re-figure out exactly what does and doesn't need to be cleaned up somehow. Far better to simply encode that into the logic of the function itself:
bool SomeFunc(void) {
bool success;
if (!(success = DoStep1()))
goto FAIL;
if (!(success = DoStep2()))
goto FAIL_CLEANUP1;
if (!(success = DoStep3()))
goto FAIL_CLEANUP2;
assert(success);
goto END;
/* error handling and return */
FAIL_CLEANUP2:
CleanUpStep2();
FAIL_CLEANUP1:
CleanUpStep1();
FAIL:
assert(!success);
END:
return success; }
If your function only needed to temporarily grab the resources and release them all before returning then it is possible to cleanly do that using nested if's, although a lot of people find that style ugly and hard to read, especially if your coding standard calls for 4 space or 8 (!) space indentation per each nesting level.
"The problem with "goto error handling" is that it is a situation that should never arise in a well designed program."
You obviously do not write much C code. Almost every non-trivial function call in a C program can fail or function abnormally. Asserting that you can somehow magically not have error detection and handling in the main flow of your C code is ridiculous.
The main reason to have a single exit point in C code is so that you can easily add exit invariant checks and/or logging or anything else you want whenever the function returns. If you have ten different returns sprinkled throughout a function you have to go and funge with all of them and convert them to the other form (i.e. - goto RETURN). Also, if you have goto error handling and cleanup code (which you almost always do anyway) you will naturally have a place for a single return point.
Please explain how else to handle error conditions sanely in C? For example, how do you cleanly implement a function that needs to acquire N resources where any one of the acquisitions can fail and on failure you need to clean up after yourself?
Explicit stack unwinding in an error condition, checking exit point invariants and a single exit point are why most C functions should use goto's in the real world.
typedef struct {
V v;
W w;
X x;
Y y;
Z z;
} Resources;
int Resources_init(Resources *r) {
int ret;
if ((ret = V_init(&r->v)))
goto FAIL;
if ((ret = W_init(&r->w)))
goto FAIL_V;
if ((ret = X_init(&r->x)))
goto FAIL_W;
if ((ret = Y_init(&r->y)))
goto FAIL_X;
if ((ret = Z_init(&r->z)))
goto FAIL_Y;
assert(0 == ret);
goto END;
/* error handling and return */
FAIL_Y:
Y_fini(&r->y);
FAIL_X:
X_fini(&r->x);
FAIL_W:
W_fini(&r->w):
FAIL_V:
V_fini(&r->v);
FAIL:
assert(0 != ret);
END:
return ret; }
Try to accomplish similar logic with nested if's and it will be garbage code. C++ has exceptions, constructors and destructors while C does not. You have to hand code the same logic unfortunately and check and handle every return for potential failure.
Really? How else do you handle error conditions and stack unwinding in C? I'd love to see you write a function that needs to acquire N resources (say N distinct mallocs) where any one of the acquisitions can fail and do it more cleanly than an approach that uses goto's to implement explicit stack unwinding in an error condition.
I'd love to see you write the error handling for a C function that needs to acquire multiple resources where any such acquisition can fail. I'll bet it is gobbledy gook.
Funny! Using goto statements is the only sane way to handle errors and stack unwinding in C. If C had exceptions that might be a different story but...
Settlement free peering between tier 1 carriers only happens when the flow of traffic is roughly balanced between the contracting peers.
When one peer is pushing a lot more traffic onto the other network, then that usually goes out the window and the pusher is required to pay the receiving network. Otherwise, networks would be monetarily incentivized to unload traffic they should carry on their own networks onto their peers' instead.
Whoops! Mis-read that somehow. I thought it said ambient temperature. The fact that they were doing it an vacuum chamber threw me off. And, yes, I know temperature in a vacuum doesn't mean a whole lot. Just read too fast.
Thank you! You beat me to posting this. From the summary:
"Thrust was observed on both test articles, even though one of the test articles was designed with the expectation that it would not produce thrust. Specifically, one test article contained internal physical modifications that were designed to produce thrust, while the other did not (with the latter being referred to as the "null" test article)."
"The cost savings of switching to an electric will be substantial..."
All the analyses I've read say that, so far, it takes a very long time for an EV's total cost to match an ICE's. As the cost of gas continues to increase, then EVs become more cost attractive.
Yes, but Musk only claims that this can shave 30% off the costs of the batteries and 3rd party analysts are skeptical of Tesla's claimed and projected costs...
Yes, but even Tesla projects that this will ultimately only shave 30% off the cost of the batteries and 3rd party analysts are skeptical of Tesla's claims on the cost of their current batteries and there ability to reduce them. It looks to me like a technology breakthrough is needed here, not just economies of scale.
"Tesla Superchargers represent the most advanced charging technology in the world, capable of charging Model S 16x faster than most public charging stations. We will soon roll out 120 kW Superchargers, which are 33% faster than our current version and can replenish half a charge in as little as 20 minutes, for free."
You know, not every function releases all the resources it claims before it returns. Sometimes acquiring those resources is exactly the reason why you called said function. Think of the initializer (or insertion into) of almost any kind of container data structure, for example.
Sure but that doesn't help people programming in C. You might as well tell them to program in Lisp because it's better.
C++ has FAR too many evil temptations in it to be allowed in many situations: the sword itself incites to violence.
C is far simpler and easy to understand what is happening.
Here's an alternate form that uses goto's:
{
if (-1 != (dest = creat("file.txt", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))) {
perror("Unable to create file.txt");
goto FAIL;
}
if (-1 != (src = open("source.txt"))) {
perror("Unable to open source.txt");
goto FAIL_DEST;
}
if (NULL != (buf = calloc(1024, 1))) {
perror("Memory allocation error");
goto FAIL_SRC;
}
if (-1 != (rd = read(src, buf, 1024))) { /* should reading zero bytes be an error? */
perror("Read failed");
goto FAIL_BUF;
}
for (total_written = 0; total_written < rd; total_written += wr, buf_p += wr) { /* TODO check errno for fixable errors like EAGAIN or EINTR */
if (-1 == (wr = write(dest, buf_p, rd-total_written))) {
perror("Error writing to file");
goto FAIL_BUF;
}
}
FAIL_BUF:
free(buf);
FAIL_SRC:
close(src);
FAIL_DEST:
close(dest);
FAIL:
}
I prefer this form because the main line execution is significantly clearer (i.e. - you don't have ever deeper nesting of the successful path), especially if you have even more resources to acquire that can fail. Also, errors are handled immediately (e.g. - the associated perror() is right there where the error is detected rather than potentially hundreds of lines below) and the main line of execution is obviously aborted and cast off to error handling / cleanup code.
An even better example would be an initializer function that only releases the acquired resources on error and on success leaves them acquired when it returns. There, the if-else structure you used won't work -- or your successful return is buried deep inside your nested successful if's with a different exit point for errors.
How about the contrived example of you actually specifying what acquireResources() should look like in C?
Why make two functions when one suffices? Especially when you already have goto error handling that naturally gives you a good spot for a single exit point anyway (as all your error exits will go out the same way)?
"Do you have multiple labels?"
Yes.
"A label for each potential failing resource?"
Yes.
"An unwound set of labels?"
You reclaim the resources in the reverse order that you acquired them so that the error handling code is common to all the error goto's. Basically an explicit form of C++'s stack unwinding and deconstructor invocation.
"What convention are you using for the labels?"
I typically name the labels as FAIL_${last_successfully_acquired_resource_name}. For example, "goto FAIL_LOCK;" for a failure that occurs after acquiring a mutex named "lock".
I keep seeing people talking about using setjmp / longjmp to handle errors and cleanup, but I'm not familiar with that style and don't see how it solves the problem.
With goto's you jump to exactly the cleanup code you need to release the resources that you have already acquired within the function -- usually in reverse order so that you are effectively doing what C++ block destructors would do automatically for you.
setjmp / longjmp would let you return to a previous point in your code but wouldn't do anything for the actual necessary cleanup unless everything was on the stack right?
Write an example that properly handles 5 different mallocs within the same function and properly cleans up after itself on failure without using goto's. Here's the goto example:
Resources *Resources_alloc(void)
{
Resources *ret;
if (NULL == (ret = malloc(sizeof(Resources))))
goto FAIL;
if (NULL == (ret->rsrc1 = malloc(sizeof(ret->rsrc1))))
goto FAIL_RESOURCES;
if (NULL == (ret->rsrc2 = malloc(sizeof(ret->rsrc2))))
goto FAIL_RSRC1;
if (NULL == (ret->rsrc3 = malloc(sizeof(ret->rsrc3))))
goto FAIL_RSRC2;
if (NULL == (ret->rsrc4 = malloc(sizeof(ret->rsrc4))))
goto FAIL_RSRC3;
assert(ret);
goto END;
/* error handling and return */
FAIL_RSRC3:
free(ret->rsrc3);
FAIL_RSRC2:
free(ret->rsrc2);
FAIL_RSRC1:
free(ret->rsrc1);
FAIL_RESOURCES:
free(ret);
ret = NULL;
FAIL:
assert(!ret);
END:
return ret;
}
Also, it isn't always the case that the thing you need to reclaim is a pointer and can be dynamically tested as to whether it was successfully acquired or not. For example, you can't test a pthread_mutex_t to see if it is valid or not. Your code has to know either based on its structure (i.e. - like the above) or you have to have a separate tracking variable per such object.
PS - Yes, the example is a bit contrived, there'd be little reason to malloc those members rather than just have them allocated as part of the Resources struct. I just did that as an illustrative example. Also, I'd typically cast the result of a malloc to the appropriate type so that a C++ compiler wouldn't complain about my code, but I haven't specified their types in this example.
Your code is actually an example of why you should use goto rather than another construct.
I notice that you left the /* Do Cleanup */ part unimplemented. Now why didn't you fill that bit in if it's so easy? I'll tell you why: all your error breakouts jump to the same spot and so your cleanup code has to re-figure out exactly what does and doesn't need to be cleaned up somehow. Far better to simply encode that into the logic of the function itself:
bool SomeFunc(void)
{
bool success;
if (!(success = DoStep1()))
goto FAIL;
if (!(success = DoStep2()))
goto FAIL_CLEANUP1;
if (!(success = DoStep3()))
goto FAIL_CLEANUP2;
assert(success);
goto END;
/* error handling and return */
FAIL_CLEANUP2:
CleanUpStep2();
FAIL_CLEANUP1:
CleanUpStep1();
FAIL:
assert(!success);
END:
return success;
}
If your function only needed to temporarily grab the resources and release them all before returning then it is possible to cleanly do that using nested if's, although a lot of people find that style ugly and hard to read, especially if your coding standard calls for 4 space or 8 (!) space indentation per each nesting level.
"The problem with "goto error handling" is that it is a situation that should never arise in a well designed program."
You obviously do not write much C code. Almost every non-trivial function call in a C program can fail or function abnormally. Asserting that you can somehow magically not have error detection and handling in the main flow of your C code is ridiculous.
The main reason to have a single exit point in C code is so that you can easily add exit invariant checks and/or logging or anything else you want whenever the function returns. If you have ten different returns sprinkled throughout a function you have to go and funge with all of them and convert them to the other form (i.e. - goto RETURN). Also, if you have goto error handling and cleanup code (which you almost always do anyway) you will naturally have a place for a single return point.
Please explain how else to handle error conditions sanely in C? For example, how do you cleanly implement a function that needs to acquire N resources where any one of the acquisitions can fail and on failure you need to clean up after yourself?
Explicit stack unwinding in an error condition, checking exit point invariants and a single exit point are why most C functions should use goto's in the real world.
typedef struct
{
V v;
W w;
X x;
Y y;
Z z;
} Resources;
int Resources_init(Resources *r)
{
int ret;
if ((ret = V_init(&r->v)))
goto FAIL;
if ((ret = W_init(&r->w)))
goto FAIL_V;
if ((ret = X_init(&r->x)))
goto FAIL_W;
if ((ret = Y_init(&r->y)))
goto FAIL_X;
if ((ret = Z_init(&r->z)))
goto FAIL_Y;
assert(0 == ret);
goto END;
/* error handling and return */
FAIL_Y:
Y_fini(&r->y);
FAIL_X:
X_fini(&r->x);
FAIL_W:
W_fini(&r->w):
FAIL_V:
V_fini(&r->v);
FAIL:
assert(0 != ret);
END:
return ret;
}
Try to accomplish similar logic with nested if's and it will be garbage code. C++ has exceptions, constructors and destructors while C does not. You have to hand code the same logic unfortunately and check and handle every return for potential failure.
Really? How else do you handle error conditions and stack unwinding in C? I'd love to see you write a function that needs to acquire N resources (say N distinct mallocs) where any one of the acquisitions can fail and do it more cleanly than an approach that uses goto's to implement explicit stack unwinding in an error condition.
I'd love to see you write the error handling for a C function that needs to acquire multiple resources where any such acquisition can fail. I'll bet it is gobbledy gook.
Funny! Using goto statements is the only sane way to handle errors and stack unwinding in C. If C had exceptions that might be a different story but ...
and not a net neutrality issue thankfully.
Settlement free peering between tier 1 carriers only happens when the flow of traffic is roughly balanced between the contracting peers.
When one peer is pushing a lot more traffic onto the other network, then that usually goes out the window and the pusher is required to pay the receiving network. Otherwise, networks would be monetarily incentivized to unload traffic they should carry on their own networks onto their peers' instead.
Whoops! Mis-read that somehow. I thought it said ambient temperature. The fact that they were doing it an vacuum chamber threw me off. And, yes, I know temperature in a vacuum doesn't mean a whole lot. Just read too fast.
Nope, they did it in a vacuum chamber ...
Thank you! You beat me to posting this. From the summary:
"Thrust was observed on both test articles, even though one of the test articles was designed with the expectation that it would not produce thrust. Specifically, one test article contained internal physical modifications that were designed to produce thrust, while the other did not (with the latter being referred to as the "null" test article)."
"The cost savings of switching to an electric will be substantial ..."
All the analyses I've read say that, so far, it takes a very long time for an EV's total cost to match an ICE's. As the cost of gas continues to increase, then EVs become more cost attractive.
Yes, but Musk only claims that this can shave 30% off the costs of the batteries and 3rd party analysts are skeptical of Tesla's claimed and projected costs ...
Yes, but even Tesla projects that this will ultimately only shave 30% off the cost of the batteries and 3rd party analysts are skeptical of Tesla's claims on the cost of their current batteries and there ability to reduce them. It looks to me like a technology breakthrough is needed here, not just economies of scale.
Scroll down on your link:
"Tesla Superchargers represent the most advanced charging technology in the world, capable of charging Model S 16x faster than most public charging stations. We will soon roll out 120 kW Superchargers, which are 33% faster than our current version and can replenish half a charge in as little as 20 minutes, for free."