Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The fact that Go's defer runs at function end instead of scope end is, in my opinion having coded and reviewed huge amounts of Go code, a bug.

It's almost never what you want, and it requires terrible gymnastics whenever the difference matters.

So in C++ implementing defer the right way is to just register a std::function that gets run from the class destructor. I've used it as an alternative to wrapping a resource, or timing a function call.

Only gotcha is to be careful about throwing from within the destructor. Or to put another way: don't.



The D Language has scope(exit), instead of defer. Example:

    scope(exit) writeln("3");
    writeln("1");
    writeln("2");
Output:

    1
    2
    3


The article references 'defer' being in several newer languages, but seems to have missed the 'scope' implementation in the D language which I think was implemented long before the other languages got their 'defer' feature.


No, I'm aware of it. GCC also has a similar feature as a C extension. I picked those languages because they very clearly use the same keyword.


I'd like "defer_func" to be an option; I do have some code that seriously uses it that way. But all in all defer defaulting to scope would be a lot more useful.

I've written some functions-in-functions solely to get "scope-like" deferral. Now, so far, none of them have ever survived refactoring, in that they've always been lifted up to become their own top-level functions where defer resumes working like I wanted anyhow. But I've also got a ton of code where the difference doesn't much matter (a function with only one scope, or where defer is only on the outer-most scope anyhow), and it still seems like scope would be a better default.


I've written this a few times:

    class defer{public:defer(std::function<()> f):f_(std::move(f)){} ~defer(){f_();}private:std::function f_;};
Then

    fd = socket(…);
    defer _([]{close(fd);});
But yeah, most of the time a refactor will instead create a proper wrapper class. It's rare that I want to RAII something, but only in some cases. E.g. I probably want RAII on FDs always, with proper ownership, not merely in some cases.

And this is also what Go missed. I'm a big fan of RAII.


No need to box with std::function. Since C++17 this is enough:

  template<class Fn>
  struct defer {
    Fn fn;
    ~defer() { fn(); }
  };
  template<class Fn>
  defer(Fn) -> defer<Fn>;

  int main() {
    defer _ { [] { std::cout << "exit"; }};
  }
Although you might want to add the ability to dismiss() the guard.

edit: a more complete implementation: https://godbolt.org/z/6675K1 . I like to name my guards. Making them anonymous is left as an exercise for the reader.


Yeah, I chose not to templatize and add dismiss() mostly to make it fit better in a comment.

But like I said at some point, if it gets complicated, then probably the value should be properly wrapped, with actual owner semantics rather than defers.


You are right in most cases. I find it useful for transactional code though, where I might be modifying a bunch of data structures and I want to undo everything on error. Doesn't really make much sense to write classes in this case if the code is really function specific.




Consider applying for YC's Winter 2027 batch! Applications are open till November 2.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: