Hacker News new | ask | show | jobs
by josephcsible 1619 days ago
No, because exiting the block early (e.g., with return) won't run the cleanup code.
1 comments

That's a little bit like saying, it's impossible to write functioning code because you could make a mistake. But an abstraction that can be misused might still be an abstraction worth using.

Here is a macro that can be used to emulate a defer

    #define CONCAT_(a, b) a ## b
    #define CONCAT(a, b) CONCAT_(a, b)
    #define UNIQUENAME() CONCAT(i_, __LINE__)

    #define SCOPE_(counter, init_stmt, exit_stmt)  for (int counter = ((init_stmt), 1); counter--; (exit_stmt))
    #define SCOPE(init_stmt, exit_stmt) SCOPE_(UNIQUENAME(), (init_stmt), (exit_stmt))
Granted it's a hack, but it can be useful at times. I've used something like it to define a large data hierarchy in code for example, as having to close all the nodes manually is tedious.

You could wrap a second for-loop around the definition of the macro to at least be able to catch misplaced "break" statements.

Looks very interesting. Can you please provide usage example?
Sure, you'd code like

    SCOPE(Resource *ptr = acquire_resource(),
          release_resource(ptr))
    {
        // do stuff with resource ptr.
    }
Actually, to allow variable declarations in the init_stmt like above, you'll need to use two nested for-loops:

    #define SCOPE_(name, begin_stmt, end_stmt) for (int name = 0; !name; assert(name && "should never break from a SCOPE")) for (begin_stmt; !name; name++, (end_stmt))
It is natural to add another layer of specific usage macro like this:

    #define UI_NODE(ctx) SCOPE(push_ui_node(ctx), pop_ui_node(ctx))

    UI_NODE(ctx)
    {
        ui_color(ctx, UI_COLOR_RED);

        const char *items[3] = { "a", "b", "c" };
        for (int i = 0; i < 3; i++)
        {
            UI_NODE(ctx)
                ui_text(ctx, items[i]);
        }
    }
Naturally, if you're already on C++, better code these macros in terms of RAII instead of abusing for-loops. That will add a little robustness.
I'm on C89, but this is a very useful trick. Thanks!