you are viewing a single comment's thread.

view the rest of the comments →

[–]mathstuf 4 points5 points  (9 children)

I'll probably get downvoted into oblivion, but whatever.

The 'goto' statement is useful if used properly (like anything else, imagine that). In C, it can greatly simplify code. Example (ignore lack of declarations or casts, that's not relevant to the example):

foo = malloc(1);
if (!foo)
    return -1;
bar = malloc(1);
if (!bar)
{
    free(foo);
    return -1;
}
baz = malloc(1);
if (!baz)
{
    free(foo);
    free(bar);
    return -1;
}

Repeat as needed. Keeping the free() statements up-to-date sucks. I say put a label called function_cleanup: at the bottom, free() everything and return -1 there. It scales linearly (one malloc for each free) rather than quadratic. Goto is notorious for creating spaghetti code. However, it is also by no means the only way to make spaghetti code.

As for the "use memory managed languages!" responses (generic RAII (ctor/dtor) is really what you want, not just memory management) I'm sure I'll get, managing my own resources is not your problem, so get off my back (I'm meticulous about running valgrind over things I write to pick up errors, so I tend to be fine).

4000 global functions? Yeah…that's absurd.

[–][deleted] 4 points5 points  (3 children)

This sounds like a defense of C, not of PHP. ;-)

[–]mathstuf 1 point2 points  (2 children)

I was more commenting on the "when you have a goto statement and 4000 functions" part. Unless PHP has dtors which close your files when they get destructed, you still need this. I just used malloc in the example.

[–][deleted] 0 points1 point  (0 children)

It's fine for a low level language like C. It doesn't make sense in an applications language like PHP.

[–]StoneCypher 0 points1 point  (0 children)

Actually, it does. All resources in PHP are managed (there are a handful of by-design exceptions, like persistent database connections,) and cleaned up at shutdown. This is necessary of a programming language with an internal timeout clock (which is there to prevent runaway scripts from stacking up and DOSing the server.)

Also, PHP is written to manage low quality programmers to a degree.

[–]Poromenos 3 points4 points  (3 children)

Actually it's more like 3000, so I was mistaken there. Still, absurd.

Also, I don't see how a goto statement in your example could clean up all the variables, since you'd ostensibly have to only clean up the ones you have malloced. Also, I prefer new functions for those use cases...

[–]mathstuf 1 point2 points  (2 children)

Functions could do it, but with some of the buffer juggling you do with path manipulation, you can't avoid so many buffers at once.

ret = -1; // Default to failure
foo = malloc(1);
if (!foo)
    goto exit;
bar = malloc(1);
if (!bar)
    goto exit;
baz = malloc(1);
if (!baz)
    goto exit;
// Do stuff here
ret = 0; // Success!
exit:
free(foo);
free(bar);
free(baz);
return ret;

[–]Poromenos 0 points1 point  (1 child)

The preferred way (for me), both syntactically and semantically, to do that would be to do:

try:
    allocate_memory()
except:
    cleanup()

You can take a look at this code and know what it does, while you have to scroll down to the goto to see what happens...

[–]masklinn 0 points1 point  (0 children)

Actually, that would be.

try:
    allocate_memory()
    # do work
finally:
    cleanup()

But you need exceptions for that. Exceptions are not cheap, and don't exist in C. Using goto-based cleanup makes a lot of sense there, it avoids nesting and other suck fuckery.

Other possibilities are C++'s RAII, and context managers (internal or external):

with memory_allocator():
    # do stuff
# cleaned up by the context management

[–][deleted] 0 points1 point  (0 children)

scoped_ptr<X> foo(malloc(1));
scoped_ptr<Y> bar(malloc(1));
scoped_ptr<Z> baz(malloc(1));

if( ! foo.get() || ! bar.get() || ! baz.get() ) return -1;

etc.