Want to read Slashdot from your mobile device? Point it at m.slashdot.org and keep reading!

 



Forgot your password?
typodupeerror

Comment: Re:Actually, ADM Rogers doesn't "want" that at all (Score 1) 406

by jschultz410 (#49121981) Attached to: NSA Director Wants Legal Right To Snoop On Encrypted Data

"The law and Constitution (as interpreted and implemented by our system of government) are the constraints -- not specific technological capability."

Complete BS.

History has proven that the primary thing that kept the 4th amendment alive for as long as it lived was the technological inability of the govt. to snoop on most aspects of its citizens lives. Now that technological progress and the digitization of our lives has made it technically possible to capture and examine grand swathes of citizens' lives, lo and behold, suddenly all those previously sacrosanct legal constraints of the past suddenly start getting REAL squishy. Suddenly, Orwellian "full capture" approaches are claimed to be NECESSARY for the govt. to properly protect the HOMELAND against Oceania. Or is it Eastasia these days? I always get it mixed up.

Worse, the military-industrial types and their security pawns in Congress actively chip away at whatever fig leafs of legal constraints still exist on govt. snooping as we've seen over the last decade and a half.

Then these same folks have the audacity to be shocked, surprised and upset when citizens and companies object to them shredding their formerly fundamental rights. They smear anyone who actively takes steps to restore a more proper balance as criminals, terrorists and traitors.

As the OP said, they can go fuck themselves. You aren't putting this genie back in the bottle.

Comment: Re:Never Use Goto (Score 1) 677

Then how do you cleanly handle a function that needs to acquire N resources where any one of the acquisitions can fail -- and it needs to clean itself up on failure (and possibly on success)?

The only non-goto answer I've seen so far is to have ever deeper nesting of if's (with a return buried in its depths if the resources should be held on success), followed by a bunch of unwinding else's that contain and separate the error handling in else's and far away from the error detection (with a different return path when the resources are held on success).

Such coding contains a bunch of anti-patterns: ArrowAntiPattern and rejects the use of GuardClauses and HandleErrorsInContext.

Meanwhile, the goto version does exactly the opposite -- it doesn't have ever deeper nesting of the common successful path, it uses guard clauses to abort further execution upon error detection, error dispatching (and any in context handling if necessary) is easily done and you can jump to exactly the right section of cleanup code and it is easy to have a single exit point for the function after all the cleanup code at the bottom of the function.

Comment: Re:What's Unique To Goto? (Score 1) 677

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.

Comment: Re:GOTO is a crutch for bad programmers (Score 1) 677

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) {
        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.

Comment: Re:why? (Score 1) 677

by jschultz410 (#49044281) Attached to: Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"

"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".

Comment: Re: why? (Score 1) 677

by jschultz410 (#49044221) Attached to: Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"

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?

Comment: Re:if (i_use_GOTOs) { goto_school(); } (Score 1) 677

by jschultz410 (#49044163) Attached to: Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"

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.

Comment: Re:why? (Score 1) 677

by jschultz410 (#49043849) Attached to: Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"

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.

Comment: Re:why? (Score 1) 677

by jschultz410 (#49043735) Attached to: Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"

"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.

Comment: Re: why? (Score 2) 677

by jschultz410 (#49043627) Attached to: Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"

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.

"Indecision is the basis of flexibility" -- button at a Science Fiction convention.

Working...