6 ms·
C++ says “We have try... finally at home”
- jasode 10mo agoThe submitted title is missing the salient keyword "finally" that motivates the blog post. The actual subtitle Raymond Chen wrote is: "C++ says “We have try…finally at home.”" It's a snowclone based on the meme, "Mom, can we get <X>? No, we have <X> at home." : https://www.google.com/search?q=%22we+have+x+at+home%22+meme https://www.google.com/search?q=%22we+have+x+at+home%22+meme In other words, Raymond is saying... "We already have Java feature of 'finally' at home in the C++ refrigerator and it's called 'destructor'" To continue the meme analogy, the kid's idea of <X> doesn't match mom's idea of <X> and disagrees that they're equivalent. E.g. "Mom, can we order pizza? No, we have leftover casserole in the fridge." So some kids would complain that C++ destructors RAII philosophy require creating a whole "class X{public:~X()}" which is sometimes inconvenient so it doesn't exactly equal "finally".
- thombles 10mo agoHN has some heuristics to reduce hyperbole in submissions which occasionally backfire amusingly.
- pjmlp 10mo agoYou have a few minutes to change the title after the submission, I do it all the time.
- tux3 10mo agoIt's rare to see the mangling heuristics improve a title these days. There was a specific type of clickbait title that was overused at the time, so a rule was created. And now that the original problem has passed, we're stuck with it.
- mort96 10mo agoYeah 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 somewhat exaggerated original post title. As it stands, the HN title suggests that Raymond thinks the C++ 'try' keyword is a poor imitation of some other language's 'try'. In reality, the post is about a way to mimic Java's 'finally' in C++, which the original title clearly (if humorously) encapsulates. Raymond's words have been misrepresented here for over 4 hours at this point. I do not understand how this is an acceptable trade-off.
- mcny 10mo agoPersonally, I would rather we have a lower bar for killing submissions quickly with maybe five or ten flags and less automated editorializing of titles.
- rramadass 10mo agoYou can always contact hn@ycombinator.com to point out errors of this nature and have it corrected by one of the mods.
- UncleMeat 10mo agoA better approach would be to not so aggressively modify headlines. Relying on somebody to detect the error, email the mods (significant friction), and then hope the mods act (after discussion has already been skewed) is not really a great solution.
- mort96 10mo agoIt has been up with the incorrect title for over 7 hours now. That's most of the Hacker News front-page lifecycle. The system for correcting bad automatic editorialisation clearly isn't working well enough.
- rramadass 10mo agoOh, come on man! These are trivial bugs. Whoever noticed it first should have sent the email to the mods. I did it before i posted my previous comment and i now see that the title has been changed appropriately.
- mort96 10mo ago7. hours.
- rramadass 10mo agoPresumably nobody informed the mods (before i did) and it was very early in the morning in the US (assuming mods are based in the US). That would explain the delay. Anyway, going forward, if anything like this happens again folks should simply shoot an email immediately to the mods and if the topic is really interesting deserving of more discussion they can always request the mods to keep the post on the frontpage for a longer time period via second-chance pool etc. It just takes a minute or two of one's time and hence not worth getting het up over.
- ibobev 10mo agoI intentionally shortened the title because there is a length limit. Perhaps I didn't do it the right way because I was unfamiliar with the mentioned meme. Sorry about that.
- vidarh 10mo agoI'm curious about the actual origin now, given that a quick search shows only vague references or claim it is recent, but this meme is present in Eddie Murphys "Raw" from 1987, so it is at least that old.
- pelorat 10mo agoSounds like a perfect fit for some Deep Research. Edit: A deep research run by Gemini 3.0 Pro says the origin is likely to be stand-up comedy routines between 1983–1987 and particularly mentions Eddie Murphy, and the 1983 socioeconomic precursor "You ain't got no McDonald's money" in Delirious (1983) culminating in the meme from in Raw (1987). So Eddie might very well be the original origin.
- deleted 10mo ago[deleted]
- locknitpicker 10mo ago> So some kids would complain that C++ destructors RAII philosophy require creating a whole "class X{public:~X()}" which is sometimes inconvenient so it doesn't exactly equal "finally". Those figurative kids would be stuck in a mental model where they try to shoehorn their ${LanguageA} idioms onto applications written in ${LanguageB}. As the article says, C++ has destructors since the "C with Classes" days. Complaining that you might need to write a class is specious reasoning because if you have a resource worth managing, you already use RAII to manage it. And RAII is one of the most fundamental and defining features of C++. It all boils down to whether one knows what they are doing, or even bothers to know what they are doing.
- afiori 10mo agoOk, but sometimes you just need a single line in a finally and writing a class is more annoying
- locknitpicker 10mo ago> Ok, but sometimes you just need a single line in a finally and writing a class is more annoying I don't think you understand. If you need to run cleanup code whenever you need to destroy a resource, there is already a special member function designed to handle that: the destructor. Read up on RAII. It somehow you failed to understand RAII and basic resource management, you can still use one-liners. Read up on scope guard. If you are too lazy to learn about RAII and too lazy to implement a basic scope guard, you can use one of the many scope guard implementations around. Even Boost has those. https://www.boost.org/doc/libs/latest/libs/scope/doc/html/scope/scope_guards.html https://www.boost.org/doc/libs/latest/libs/scope/doc/html/sc... So, unless you are lazy and want to keep mindlessly writing Java in ${LANGUAGE} regardless it makes sense or not, there is absolutely no reason at all to use finally in C++.
- AnimalMuppet 10mo agoSlightly more than that: If you need to run cleanup code, whatever needs cleaned up should be a class and do the cleanup in the destructor. Take a file handle, for instance. Don't use open() or fopen() and then try to close it in a finally. Instead, use a file class and let it close itself by going out of scope.
- coliveira 10mo agoThat's why you shouldn't use memes in the titles of technical articles. The intelligibility of your intent is vastly reduced.
- mort96 10mo agoThe title of the blog post is perfectly intelligible. It becomes unintelligible when you remove random words from it.
- otterley 10mo agoIt didn’t make sense to me, either, and I’m a native English speaker. The cultural reference was lost on me.
- afiori 10mo agoThe requirement to avoid any cultural reference is a bit strict
- ModernMech 10mo agoIt still didn't make sense to me with all the words. The way it finally made sense was seeing the formatting is "We have `try...finally` at home".
- mojuba 10mo agoI 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`.
- dwattttt 10mo agoI 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/ https://docs.rs/defer-rs/latest/defer_rs/
- deleted 10mo ago[deleted]
- mojuba 10mo agoI 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 }
- ninkendo 10mo agoEDIT: 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() }
- mojuba 10mo ago
- tryfinally 10mo agoI always wonder whether C++ syntax ever becomes readable when you sink more time into it, and if so - how much brain rewiring we would observe on a functional MRI.
- sigmoid10 10mo agoIt does... until you switch employers. Or sometimes even just read a coworker's code. Or even your own older code. Actually no, I don't think anyone achieved full readability enlightenment. People like me just hallucinated it after doing the same things for too long.
- usrnm 10mo agoAnd yet, somehow Lisp continues to be everyone's sweetheart, even though creating literal new DSLs for every project is one of the features of the language.
- vkazanov 10mo agoLisp doesnt have much syntax to speak of. All of the DSLs use the same basic structure and are easy to read. Cpp has A LOT A of syntax: init rules, consts, references, move, copy, templates, special cases, etc. It also includes most of C, which is small but has so many basic language design mistakes that "C puzzles" is a book.
- lmz 10mo agoThe syntax and the concepts (const, move, copy, etc) are orthogonal. You could possibly write a lisp / s-exp syntax for c++ and all it would make better would be the macros in the preprocessor. The DSL doesn't have to be hard to read if it uses unfamiliar/uncommon project specific concepts.
- vkazanov 10mo agoYes, sure. What i mean is that in cpp all the numerous language features are exposed through little syntax/grammar details. Whereas in Lisps syntax and grammar are primitive, and this is why macros work so well.
- winternewt 10mo agoDestructors 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 created that require nested try... finally blocks. Not to mention how branching and conditional initialization complicates things. You can often pair up constructors with destructors in the code so that it becomes very obvious when resource acquisition and release do not match up.
- jchw 10mo agoDestructors 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 dislike that aspect of exceptions, and generally prefer something closer to std::expected or Rust Result.)
- mort96 10mo ago> 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 deterministically at the end of a scope. Python's 'with' syntax comes to mind, but that's very different from C++ and Rust style destructors since you have to explicitly ask the language to clean up resources with special syntax. Which languages am I missing which have both try..finally and destructors?
- dist-epoch 10mo agoTechnically CPython has deterministic destructors, __del__ always gets called immediately when ref count goes to zero, but it's just an implementation detail, not a language spec thing.
- NooneAtAll3 10mo ago> Update: Adam Rosenfield points out that Python 3.2 now saves... how old is this post that 3.2 is "now"?
- tln 10mo agoI think the author didn't check the age of Python 3.2 when adding the update
- reactordev 10mo agoIn other words: Footgun #17421 Exhibit A.
- josefx 10mo agoWhat the blog doesn't mention is how try finally can mess up your control flow. In Java the following is perfectly valid: try { throw new IllegalStateException("Critical error"); } finally { return "Move along, nothing to see here"; }
- reactordev 10mo agoYes, Java has footguns too. The existence of two different patterns each with their own pitfalls is why we can’t have nice things. Finally shouldn’t return a value. Simply a void expression. Exception driven API’s need to be snuffed out. If your method throws, mark it as such as force me to handle the exception if it does, do not return a non-value value in a finally. Using Java as the example shows just how far we have come with this thinking, why old school Java style exception handling sucks and why C++ by proxy does too. It’s difficult to break old mental habits but it’s easier when the compiler yells at you for doing bad things.
- Maxatar 10mo agoWhy is this a footgun? This seems no different than using a try/catch. try { throw new IllegalStateException("Critical error"); } catch(Exception) { return "Move along, nothing to see here"; }
- firesteelrain 10mo agoThis is a good “how C++ does it” explanation, but I think it’s more accurate to say destructors implement finally-style cleanup in C++, not that they are finally. finally is about operation-scoped cleanup; destructors are about ownership. C++ just happens to use the same tool for both.
- meindnoch 10mo agoCalling arbitrary callbacks from a destructor is a bad idea. Sooner or later someone will violate the requirement about exceptions, and your program will be terminated immediately. So I'd only use this pattern in -fno-exceptions projects. In a similar vein, care must be taken when calling arbitrary callbacks while iterating a data structure - because the callback may well change the data structure being iterated (classic example is a one-shot event handler that unsubscribes when called), which will break naïvely written code.
- fjjdrnrbbrb 10mo agoThrowing exceptions in destructors in C++ is fine, as long as your code is exception safe. What exactly are you referring to?
- meindnoch 10mo agoThrowing exceptions from destructors is "fine", except when the destructor is executed by stack unwinding (triggered by an earlier exception), in which case throwing will terminate the program with std::terminate.
- kentonv 10mo ago> In Java, Python, JavaScript, and C# an exception thrown from a finally block overwrites the original exception, and the original exception is lost. Pet peeve of mine: all these languages got it wrong. (And C++ got it extra-wrong.) The error you want to log or report to the user is almost certainly the original exception, not the one from the finally block. The error from the finally block is probably a side effect of the original exception. Reporting the finally exception obscures information about the root cause, making it harder to debug the problem. Many of these languages do attach the original exception to the new exception in some way, so you can get at it if you need to, but whatever actually catches and logs the exception later has to go out of its way to make sure to log the root cause rather than some stupid side effect. The hierarchy should be reversed: the exception thrown by `finally` should be added as an attachment to the original exception, perhaps placed in a list of "secondary" errors. Or you could even just throw it away, honestly the original exception is almost always all you care about anyway. (C++ of course did much worse by just crashing in this scenario. I imagine this to be the outcome of some debate in the committee where they couldn't decide which exception should take priority. And now everyone has internalized this terrible decision by saying "well, destructors shouldn't throw" without seeming to understand that this is equivalent to saying "destructors shouldn't have bugs". WELL OF COURSE THEY SHOULDN'T BUT GOOD LUCK WITH THAT.)
- uncivilized 10mo agoThis part is not correct. I can't speak for the other languages, but in Python the exception that is originally thrown is the one that creates the traceback. If the finally block also throws an exception, then the traceback includes that as additional information. The author includes an addendum, yet he is still wrong about which exception is first raised.
- fooofw 10mo agoI believe this might be slightly imprecise also. The traceback is actually shown based on the last-thrown exception (that thrown from the finally in this example), but includes the previous "chained exceptions" and prints them first. From CPython docs [1]: > When raising a new exception while another exception is already being handled, the new exception’s __context__ attribute is automatically set to the handled exception. An exception may be handled when an except or finally clause, or a with statement, is used. [...] The default traceback display code shows these chained exceptions in addition to the traceback for the exception itself. [...] In either case, the exception itself is always shown after any chained exceptions so that the final line of the traceback always shows the last exception that was raised. So, in practice, you will see both tracebacks. However, if you, say, just catch the exception with a generic "except Exception" or whatever and log it without "__context__", you will miss the firstly thrown exception. [1]: https://docs.python.org/3.14/library/exceptions.html#exception-context https://docs.python.org/3.14/library/exceptions.html#excepti...
- greesil 10mo agoWho needs finally when we have goto?
- Rochus 10mo agoe.g. people who use exceptions and don't use destructors?
- zvvnkjvxd 10mo agoI'm quite sure that an exception thrown in finally block in java will have the original as suppressed, not discarded
- cjj_swe 10mo agoI was hoping absl::Cleanup would get a shoutout. I worked hard to make it ergonomic and performant. For those looking for something (imo) better than the standard types, check it out!
- hindustanuday 10mo ago[dead]