logoalt Hacker News

mojubatoday at 10:21 AM3 repliesview on HN

I like how Swift solved this: there's a more universal `defer { ... }` block that's executed at the end of a given scope no matter what, and after the `return` statement is evaluated if it's a function scope. As such it has multiple uses, not just for `try ... finally`.


Replies

Someonetoday at 1:12 PM

I think Swift’s defer (https://docs.swift.org/swift-book/documentation/the-swift-pr...) was inspired by/copied from go (https://go.dev/tour/flowcontrol/12), but they may have taken it from an even earlier language that I’m not aware of.

Defer has two advantages over try…finally: firstly, it doesn’t introduce a nesting level.

Secondly, if you write

       foo
       defer revert_foo
, when scanning the code, it’s easier to verify that you didn’t forget the revert_foo part than when there are many lines between foo and the finally block that calls revert_foo.

A disadvantage is that defer breaks the “statements are logically executed in source code order” convention. I think that’s more than worth it, though.

show 2 replies
dwattttttoday at 10:55 AM

I was contemplating what it would look like to provide this with a macro in Rust, and of course someone has already done it. It's syntactic sugar for the destructor/RAII approach.

https://docs.rs/defer-rs/latest/defer_rs/

show 2 replies
troglo-bytetoday at 11:43 AM

    #include <iostream>
    #define RemParens_(VA) RemParens__(VA)
    #define RemParens__(VA) RemParens___ VA
    #define RemParens___(...) __VA_ARGS__
    #define DoConcat_(A,B) DoConcat__(A,B)
    #define DoConcat__(A,B) A##B
    #define defer(BODY) struct DoConcat_(Defer,__LINE__) { ~DoConcat_(Defer,__LINE__)() { RemParens_(BODY) } } DoConcat_(_deferrer,__LINE__)

    int main() {
        {
            defer(( std::cout << "Hello World" << std::endl; ));
            std::cout << "This goes first" << std::endl;
        }
    }
show 4 replies