Hacker News new | ask | show | jobs
by AlotOfReading 578 days ago
C++ has lifetime rules just like Rust. They're simply implicit in the code and not enforced by the compiler. Do you prefer the uncertainty of silent miscompilations and undefined behavior to upfront compiler errors?

You're already using a language with a strong type system, so it's confusing to me why you would choose to draw the line here.

3 comments

> Do you prefer the uncertainty of silent miscompilations and undefined behavior to upfront compiler errors?

Yes because then I don't have to spend hours writing esoteric spaghetti code to prove something to the compiler that is trivially known to be true. Your error is assuming static lifetime checking is free. As an engineer, I use judgement to make context-dependent trade offs.

If you like playing the compiler olympics, or your employer forces you to, please use Rust.

"Trivially known to be true" until the code evolves making your unstated assumptions not hold and everything breaks, often in complex and unintuitive ways involving interactions across modules. This is why these automated soundness checks are valuable.
"until the code evolves [...]"

That is already a desirable place to be, where you managed to get a working implementation ready to evolve. My issue with opinionated languages like Rust is that they make development more expensive. I then afford to pay the necessary work-effort for fewer projects than I otherwise could if I was to focus more on the problem(s) at hand instead of that and other mandatory constraints forced upon me by the compiler. I very much want my development tools to limit themselves on being tools, to assist me on the part of the problem I chose to focus on with little to no cost paid for their usage. I want to be able to focus on prototyping some working solution first, and only then, if the project's needs really warrant it, to switch on paying the development cost for other aspects, be it safety or whatnot.

> Yes because then I don't have to spend hours writing esoteric spaghetti code to prove something to the compiler that is trivially known to be true.

And that’s exactly the reason why we need more safety in C++.

I’m terrified at amount of code in real world written with this mindset.

At the same time, you should recognize that not all real code in the world is used to run planes & thermonuclear power plants. For a lot of the business software, it's actually fine if it's not perfectly safe. So if it's cheaper/ faster to develop it without paying the price of static safety checks, who is to say that this was a bad tradeoff?

I actually love the ideas that Rust brought forth. It definitely has a place in the ecosystem, and I'm glad to hear critical software is being rewritten in Rust! But that doesn't mean that C++ should copy it.

C++ doesn't permit you to write code that's not perfectly safe. By using a C++ compiler, you're promising that you will write safe code even if the compiler can't verify that, lest nasal demons and other misfortunes fall upon you. If your code isn't safe and you expect that to be fine, you're not writing C++. This is a discussion about C++, so the default assumption is that you'll pay the costs of safe code instead of inventing an ill-specified dialect that happens to do what you want when it's shoved into a C++ compiler.

If you think we should instead evolve C++ so that safety isn't mandatory I'm right there with you, but it's not where the language is today and that discussion has also been shut down by the evolution working group. Moreover, Bjarne's policies mean that telling the critical software people to go fuck off to a different language fundamentally isn't part of the plan either.

It is kindof an interesting point you bring up here. However, it's also true that languages (and software in general) are what people make of it, not necessarily what their creators intended. I do believe that the stuff that happens to do what you want when shoved into a C++ compiler _is_, for all intents and purposes, C++. And I kinda' think/feel that that is also what the committee is saying - "we want C++ to keep doing that, rather than evolve into a safer thing that is no longer C++"
I get the argument, but the community argument doesn't actually change anything. No compiler will guarantee any particular behavior in the presence of memory safety issues. Very few programs happily tolerate random memory corruption or race conditions, etc.
> For a lot of the business software, it's actually fine if it's not perfectly safe.

Is it fine if it silently gives the wrong answer? If so, why are you bothering with the software at all?

In my experience all nontrivial C++ codebases have silent memory corruption bugs (at least when built with popular compilers).

Well, let's put it like this:

- Webkit, GCC, and a few others are non-trivial C++ codebases that are (I argue) useful.

- In your experience, since they are non-trivial, they have silent memory corruption bugs (i.e. they are not "perfectly safe").

Does this answer the "why bother with software at all" question?

Most C++ developers care greatly about the quality of their code, and suggesting that since the code isn't in a life threatening situation like a flight controller or medical device it can be buggy with no repercussions is pretty silly.

Your examples of GCC and Webkit are both projects that have spent enormous amounts of effort to be as memory safe as they can be, and have both had many memory safety related CVEs in the past. As was already pointed out, you still have to pay the cost of engineering memory safe code, even when your compiler/static analysis doesn't have your back.

Webkit, as I understand it, is not really a C++ codebase built with a popular compiler, it's a codebase that follows its own significantly stricter standards and has a lot of additional tooling to avoid bugs.

And I'd say that even with all that additional effort, it has a level of bugs that's not "fine". Indeed, per the article, I suspect that the maintainers of Webkit are some of the people pushing to make C++ more Rust-like.

I've found that often when I am writing esoteric spaghetti rust code... I need to start thinking about what I am trying too do! Most of the time it's a bad idea :)
If one needs to "prove something to the compiler" it is usually something both complex and against the grain; on the other hand lifetime annotations are usually just "promise something to the compiler" to allow it to make a better job.
> As an engineer, I use judgement to make context-dependent trade offs.

Well said.

This is why i am firmly in the Stroustrup camp of backward compatibility/zero overhead/better-C/etc. goodness of "old C++". I need to extend/maintain/rewrite tons of them and that needs to be as painless as possible. The current standards trajectory needs to be maintained.

The OP article is a rather poor one with no insights but mere hoopla over nothing.

If it's hoopla over nothing, why do you firmly identify with one of the factions defined by the article?
What a silly question! There is no major schism in the C++ community as the article implies; merely a strong difference of opinion on certain proposals. This is normal in any committee. But since people are strongly wedded to their own proposals it might seem more severe than it actually is.
> to prove something to the compiler that is trivially known to be true

I don't think you've ever done any serious work with lifetimes. I've been a rust developer for a number of years, and I have never once encountered a situation where the rust compiler forces me to add annotations for something which is trivially true. Never.

What actually happens is 95% of the time I never have to add lifetime annotations anyway because the compiler infers the correct annotation from the lifetime elision rules. The remaining 1 in 20 instances is when the borrow checker yells at me, and literally every single time it is due to a latent logic bug in my code. For example, accessing memory after it's been freed, or using a container after it has been consumed. Stuff that C++ would call "undefined behavior" and are generally considered Very Bad Things by C++ developers as well.

It boggles my mind that you don't want the compiler to tell you that “you have a logic error here.”

LOL; someone has definitely played with type-systems here.
> C++ has lifetime rules just like Rust. They're simply implicit in the code and not enforced by the compiler.

The problem is that the rules enforced by Rust is not restricted to lifetime rules, it's a much much larger superset that includes quite a lot of safe, legitimate and valid code.

Sure, but that's not a design philosophy C++ adheres to. Look at the modern C++ guidelines or profiles. The entire point is to rule out large swathes of safe, legitimate, and valid code in an optional and interoperable way.

C++ isn't beholden to Rust's trade-offs either. There's a whole spectrum of possibilities that don't require broken backwards compatibility. Hence: "Why draw the line specifically at lifetime annotations?"

That's what the unsafe keyword is for.
> You're already using a language with a strong type system

I'll have you know I made a variable void* just yesterday, to make my compiler shut up about the incorrect type :D