Hacker News new | past | comments | ask | show | jobs | submit login

> It's clearly possible for C++ compilers to do this in many more cases. [...] Why not use that knowledge more often to help the programmer instead of burdening them?

Because it'd break code. I explained in another comment here: https://news.ycombinator.com/item?id=19634423




> Because it'd break code.

Then that's an indictment of the decisions that led to such code being written in the first place.


Only if you're quick to judge without understanding why such code is and will continue to be written.


You're pretty quick to assume I don't. Believe me, I understand. I just don't agree that it's a good idea to mix up object lifetimes and execution context by using destructors to "magically" release locks etc. It never was. The mistakes were made years ago.

I'm not quick to judge (in this case). I'm judging after careful consideration, because I know the difference between good and bad patterns. The ones being hasty are those who mistake their own comfort level with something (often because they know nothing else) for actual merit.


RAII is one of the core language feature of C++.

Replacing it with defer or GC will surely break existing programs.

It would make sense ONLY if you want to have a new language.


> It would make sense ONLY if you want to have a new language.

Are you seriously suggesting that C++ with defer is a new language? Unlike, say, C++ with lambdas? That's just silly.


C++ without deterministic destructors to manage lifetime would be a (fundamentally) different language.

Furthermore, also disagree with you that it would be a better language. C++ has many warts but object lifetime and RAII is amongst its strong suits (unarguably, I thought — yes, resource lifetime is complex, but it’s inherently so; C++ just makes the complexity explicit and handles it in a good way). Handling resource lifetime in languages with nondeterministic GCs can be such a pain that it has fundamental, detrimental impact on the architecture. Just look at .NET’s handling of `Dispose`. I’ve written a ton of .NET GUI code, and handling resource lifetime (in particular GDI+) is an absolute pain point, which is uniquely caused by the lack of deterministic object lifetime.


> C++ without deterministic destructors to manage lifetime would be a (fundamentally) different language.

The problem is that it's not usefully deterministic once you add in exceptions, shared pointers, move semantics, lambda captures, etc. Not to mention every perverse combination of those things. Yes, it's deterministic in the tautological sense that almost everything is deterministic given enough information, but I'm not sure that's enough even for the people who write the compilers. Even they have bugs related to misunderstanding this "deterministic" system. I certainly wouldn't want to make it less deterministic, and defer certainly doesn't make it so.

> resource lifetime is complex, but it’s inherently so

A certain amount of complexity is natural, a certain amount is spurious and self-inflicted. See above for some of the causes of that spurious complexity.

> C++ just makes the complexity explicit

Being explicit about memory management isn't a goal. C is even more explicit about these things. Does that make it a better language? Even in C++, new/delete is more explicit than most of the current idioms, and every book on modern C++ recommends against them. Explicit memory management should be a last resort, for the cases not handled cleanly by the language's other constructs, and those should be kept to a minimum. C++ has notably failed at that. Literally every other popular language except for C does better.

> Handling resource lifetime in languages with nondeterministic GCs can be such a pain

Do you really see no alternatives between dumping all memory-management complexity on the programmer and a full tracing GC? The authors of Objective C's automatic reference counting or Rust's borrow checker might take issue with that, as would the people who developed the memory-lifetime rules and infrastructure for all of the bigger older C codebases I mentioned in another comment. It is in fact possible for object lifetimes to be far more deterministic than in C++ as it exists today, and I for one think that would be a good thing.


> The problem is that it's not usefully deterministic once you add in exceptions, shared pointers, move semantics, lambda captures, etc.

No, it really is, even in the presence of the things you mentioned. That’s the whole point.

> Being explicit about memory management isn't a goal. […]

I get the impression that you’re confusing explicit and manual memory management. They’re not the same.

> Do you really see no alternatives between dumping all memory-management complexity on the programmer and a full tracing GC?

Of course I do, but the alternatives aren’t without their own problems. I’m curious how Rust will fare but Objective C’s ARC, while attractively simple, has performance implications, and then there’s the problem with cycles.


Rust has ARC and RC, which I gather are badly overused by refugees from other languages dependent on GC.

The better programs and libraries use them less. It remains to be seen whether this aesthetic will win out.


> The problem is that it's not usefully deterministic once you add in exceptions, shared pointers, move semantics, lambda captures, etc. Not to mention every perverse combination of those things.

It really is though, and I can't stress that enough. I feel you just throwing out keywords to make it sound more complex than it is.


> I can't stress that enough.

You can stress an untrue statement all you like. Shout it to the heavens. It will still be untrue.

Thought for you to consider: the behavior might seem predictable to you but that's not a relevant standard. A chess opening, a volleyball play, a snowboard run might all seem straightforward to me, but that doesn't mean they'd suit everyone. It doesn't mean they're the best. It just means I've invested my time in learning to do those things those ways. It's too easy to say everyone should have to memorize the same lists of rules, to retreat into "we don't care about the blubs" arrogance, ignoring the fact that it just doesn't have to be that way. It is in no way necessary, for any purpose, to make every single programmer in a language spend so much of their time looking over their shoulder to make sure the compiler is doing the right thing. It's a waste no matter how good those programmers are.

> I feel you just throwing out keywords

And I feel that you're just not even trying to understand their relevance because you've already decided on a conclusion. The lengths to which people in this thread go to rationalize the time they've already wasted is astonishing. People who use C++ should be the first to demand its improvement, but I guess not all humans are rational.


You might have picked the wrong hill to die on.

C++ destructors really are deterministic, even in the face of exceptions, lambdas, and moves: everything constructed gets destroyed. Modern wrinkles where the compiler is allowed to skip a construction and a destruction do not contradict that. You have to fool with heap memory or evoke UB to escape that law.


To be useful, determinism has to mean not only that something happens but that it happens at a predictable time. Otherwise you're into that tautological "everything is deterministic" territory, and you step into that even deeper when you acknowledge the "modern wrinkles". "Compiler is allowed" (but not required) is practically the definition of non-determinism.


"Compiler is allowed" not to destroy what it never constructed.

This is no different from the myriad other elisions modern compilers do -- and that CPU cores do.

Deterministically, destructors run exactly when the constructed object goes out of scope, after objects constructed later, before those constructed earlier. More determinism than that is something you will get from nobody.

You don't have to write any constructors at all. Write ordinary functions, and call them whenever you like. Been there, had enough of that for several lifetimes. Destructors are better.


The behavior is predictable to anyone versed in the language. C++ is a complex language to learn so that is inherently harder than most alternatives, but the concepts here are not.

I am first in line to acknowledge the flaws of C++ as well as sheering on more modern approaches. But I do find your criticisms shallow and a quite oddly chosen.


> The behavior is predictable to anyone versed in the language.

Ahh, there's that "don't care about the blubs" arrogance again. Never mind that your interlocutor is about 99.9% likely to be less of a blub than you are. Whether behavior is predictable given arbitrary amounts of information and effort is not the point. What matters is how much it distracts the programmer from the non-language-specific problem they're really trying to solve, and the answer for C++ remains way too damn much even when the programmer is highly skilled and well versed in the language.


You know you reek of it yourself.

C++ and even C has tons of subtle edges that are impossible to keep track of. You need to be experienced to have a fighting chance, I'm not defending that. But it is a fact of life and in a large part of that are relics from the past.

You can't just take a concept that is somewhat unique to C++ and proclaim that it is bad just because C++ has a lot of warts. Your criticism doesn't even register on the weirdness scale in my opinion. It works as intended, is easy to reason about and solves practical problems. Object lifetimes is something I almost always miss when I don't use C++. A garbage collector is hell to work with in comparison.

What is unfortunate is that we don't really have any alternatives. Rust shows promise but we've had to suffer through decades to even get to this point, which also implies that we have decades left. And that assumes that rust continues in the pace it has and preferably also that we get more alternatives to chose from.


Your proposed better pattern to follow when one needs a finally block in C++ is...?


I already mentioned "defer" as in Go or Zig. It's explicitly tied to scope exit, not object lifetime, so it avoids all of the problems inherent in confusing the two.


I didn't ask what language you would use. I asked what you would do in C++, given you're criticizing people for writing such code in the language. If you're put so much thought into this problem like you claim then surely you must have a better alternative in mind.


I don't care what people "would do" in C++ today, because my whole point is that C++ started down this bad path years ago. I'm not criticizing people for writing such code. I'm criticizing the standards-makers who made such hacks (seem) necessary. It's not about having put thought into it either. Lots of people had put plenty of thought into it when the various versions of C++ were standardized. This is about making the right choices from among the alternatives available, and that was not done.

Demanding a solution that is both applicable to C++ as it exists today and yet not in C++ today is demanding two contradictory things. It's demanding that the same thing both did and didn't happen. It's dishonest. You want a suggestion? Adopt "defer" for the next version of C++. It's the best we can do. We can't change the past, but we can learn from it if we don't get stuck trying to excuse past mistakes and attack those who point them out.




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

Search: