Live data from Hacker News

C++ says “We have try... finally at home”

devblogs.microsoft.com

41–50 of 152 posts

Re: C++ says “We have try... finally at home”

#41
post #38
post #25

Earlier quoted context omitted.

> Most of the languages that have finally clauses also have destructors. Hm, is that true? I know of finally from Java, JavaScript, C# and Python, and none of them have proper destructors. I mean some of them have object finalizers which can be used to clean up resources whenever the garbage collector comes around to collect the object, but those are not remotely similar to destructors which typically run determinist…

I don't view finalizers and destructors as different concepts. The notion only matters if you actually need cleanup behavior to be deterministic rather than just eventual, or you are dealing with something like thread locals. (Historically, C# even simply called them destructors.)

There's a huge difference in programming model. You can rely on C++ or Rust destructors to free GPU memory, close sockets, free memory owned through an opaque pointer obtained through FFI, implement reference counting, etc.

I've had the displeasure of fixing a Go code base where finalizers were actively used to free opaque C memory and GPU memory. The Go garbage collector obviously didn't consider it high priority to free these 8-byte objects which just wrap a pointer, because it didn't know that the objects were keeping tens of megabytes of C or GPU memory alive. I had to touch so much code to explicitly call Destroy methods in defer blocks to avoid running out of memory.

Re: C++ says “We have try... finally at home”

#42
post #3

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

#include #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

"We have syntax macros at home"

Re: C++ says “We have try... finally at home”

#43
post #9
post #5

Earlier quoted context omitted.

HN has some heuristics to reduce hyperbole in submissions which occasionally backfire amusingly.

Yeah it's a huge mistake IMO. I see it fucking up titles so frequently, and it flies in the face of the "do not editorialise titles" rule: [...] please use the original title, unless it is misleading or linkbait; don't editorialize. It is much worse, I think, to regularly drastically change the meaning of a title automatically until a moderator happens to notice to change it back, than to allow the occasional somewha…

You can always contact hn@ycombinator.com to point out errors of this nature and have it corrected by one of the mods.

Re: C++ says “We have try... finally at home”

#44
post #33
post #6

Earlier quoted context omitted.

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/

I don't know Rust but, can this `defer` evaluate after the `return` statement is evaluated like in Swift? Because in Swift you can do this: func atomic_get_and_inc() -> Int { sem.wait() defer { value += 1 sem.signal() } return value }

EDIT: I don’t think you can actually put a return in a defer, I may have misremembered, it’s been several years. Disregard this comment chain.

It gets even better in swift, because you can put the return statement in the defer, creating a sort of named return value:

    func getInt() -> Int {
        let i: Int // declared but not
                   // defined yet!

        defer { return i }

        // all code paths must define i
        // exactly once, or it’s a compiler
        // error
        if foo() {
            i = 0
        } else {
            i = 1
        }

        doOtherStuff()
    }

Re: C++ says “We have try... finally at home”

#45
post #38
post #25

Earlier quoted context omitted.

> Most of the languages that have finally clauses also have destructors. Hm, is that true? I know of finally from Java, JavaScript, C# and Python, and none of them have proper destructors. I mean some of them have object finalizers which can be used to clean up resources whenever the garbage collector comes around to collect the object, but those are not remotely similar to destructors which typically run determinist…

I don't view finalizers and destructors as different concepts. The notion only matters if you actually need cleanup behavior to be deterministic rather than just eventual, or you are dealing with something like thread locals. (Historically, C# even simply called them destructors.)

Sometimes „eventually“ is „At the end of the process“. For many resources this is not acceptable.

Re: C++ says “We have try... finally at home”

#46

Destructors are vastly superior to the finally keyword because they only require us to remember a single time to release resources (in the destructor) as opposed to every finally clause. For example, a file always closes itself when it goes out of scope instead of having to be explicitly closed by the person who opened the file. Syntax is also less cluttered with less indentation, especially when multiple objects are…

Python has that too, it's called a context manager, basically the same thing as C++ RAII. You can argue that RAII is more elegant, because it doesn't add one mandatory indentation level.

It's not the same thing at all because you have to remember to use the context manager, while in C++ the user doesn't need to write any extra code to use the destructor, it just happens automatically.

Re: C++ says “We have try... finally at home”

#47
post #38
post #25

Earlier quoted context omitted.

> Most of the languages that have finally clauses also have destructors. Hm, is that true? I know of finally from Java, JavaScript, C# and Python, and none of them have proper destructors. I mean some of them have object finalizers which can be used to clean up resources whenever the garbage collector comes around to collect the object, but those are not remotely similar to destructors which typically run determinist…

I don't view finalizers and destructors as different concepts. The notion only matters if you actually need cleanup behavior to be deterministic rather than just eventual, or you are dealing with something like thread locals. (Historically, C# even simply called them destructors.)

> I don't view finalizers and destructors as different concepts.

They are fundamentally different concepts.

See Destructors, Finalizers, and Synchronization by Hans Boehm - https://dl.acm.org/doi/10.1145/604131.604153

Re: C++ says “We have try... finally at home”

#48
post #3

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

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.

Re: C++ says “We have try... finally at home”

#49
post #25
post #22

Earlier quoted context omitted.

Destructors and finally clauses serve different purposes IMO. Most of the languages that have finally clauses also have destructors. > Syntax is also less cluttered with less indentation, especially when multiple objects are created that require nested try... finally blocks. I think that's more of a point against try...catch/maybe exceptions as a whole, rather than the finally block. (Though I do agree with that. I d…

> Most of the languages that have finally clauses also have destructors. Hm, is that true? I know of finally from Java, JavaScript, C# and Python, and none of them have proper destructors. I mean some of them have object finalizers which can be used to clean up resources whenever the garbage collector comes around to collect the object, but those are not remotely similar to destructors which typically run determinist…

In C# the closest analogue to a C++ destructor would probably be a `using` block. You’d have to remember to write `using` in front of it, but there are static analysers for this. It gets translated to a `try`–`finally` block under the hood, which calls `Dispose` in `finally`.

    using (var foo = new Foo())
    {
    }
    // foo.Dispose() gets called here, even if there is an exception
Or, to avoid nesting:

    using var foo = new Foo(); // same but scoped to closest current scope
These also is `await using` in case the cleanup is async (`await foo.DisposeAsync()`)

I think Java has something similar called try with resources.

Re: C++ says “We have try... finally at home”

#50

Destructors are vastly superior to the finally keyword because they only require us to remember a single time to release resources (in the destructor) as opposed to every finally clause. For example, a file always closes itself when it goes out of scope instead of having to be explicitly closed by the person who opened the file. Syntax is also less cluttered with less indentation, especially when multiple objects are…

But they're addressing different problems

Sure destructors are great but you still want a "finally" for stuff you can't do in a destructor

Post reply on HN