Hacker News new | ask | show | jobs
by dannymi 1422 days ago
>The bad C++ code is in the very first line of the "make_appender" definition: capturing the closure's environment by reference is nonsense: It is equivalent to returning a reference to an argument.

If it is so bad, it should (in the sense of how things would be in an ideal world) not compile.

>It is not, then, a closure at all.

It is a closure because all variables are closed-over and there are no free variables in the lambda body anymore. That is the definition of closure.

>But using a wrong function and getting wrong results is not surprising.

In an ideal world, there should be a compilation error. (There is in Rust)

The majority of what's wrong in C++ is that it lets you do nonsensical (even dangerous) things, most of the time without even a warning (and not because it's technically impossible to warn--it just didn't occur to them). It's okay to acknowledge that--it's a product of its time.

>Returning that fake closure should evoke a compiler warning, if you turn on warnings.

That "should" tells me all I need to know. In the end either safety is important, or it isn't. Choose accordingly.

3 comments

> If it is so bad, it should (in the sense of how things would be in an ideal world) not compile.

Yes, C++ can be a bad solution to a lot of problems, and that's okay. Use rust if you need a machine guarantee for memory safety (or you just like the language), you can use Go if you just don't care about that at all and want the language to take care of it. But you can use C++ for non-critical software that needs to be fast (games come to mind). Rust can be too much of a mental overhead than it's worth for some.

That closure is just not a good example. Nobody would write this, because when writing C++ code you _do_ think about whether you want a reference or not. Sure, a lot of bugs can happen but this is not, in my opinion, one of them.

If you want to prove a point, prove it fairly.

Note: I don't use C++ anymore, and I don't like it very much for other reasons.

> Rust can be too much of a mental overhead than it's worth for some.

Rust has the least mental overhead of any language I've ever used. The compiler literally takes all the mental overhead away.

> The compiler literally takes all the mental overhead away.

Increasing the strictness of the language has one effect: decreasing the number of potential solutions for a given problem.

If the restrictions are carefully chosen (like they are in rust) this leads to generally safer code. But don't fool yourself, the restrictions don't merely generate new solutions - they reject the ones that don't pass the tests.

A more extreme example is formal theorem provers. Carefully constructed proofs will take a lot of effort, but it will also make you confident that the code does what it needs to do.

The rust borrow checker is just a more restricted theorem prover that doesn't touch the logic, it just deals with the memory side of things. It's indeed very helpful in trying to explain what's wrong (and even suggest fixes), but it doesn't take the programmer overhead away.

In a more complex system rust inevitably makes it harder to come up with solutions. It will reject valid code just because it can't prove it's right, not because it's actually wrong. As a programmer, you're going to come up with such solutions, and while in time you get more used to writing code that rust likes, and rust too gets better at accepting correct solutions, you're going to have to fight the borrow checker sometimes.

I don't have a ton of experience with rust, but I encountered cases where equivalent C++ code would've worked just fine, but I had to change it because rust didn't like it.

Rust is an amazing language, but it definitely doesn't 'take all the mental overhead away'.

"Doctor, it hurts when I do that!"
Pain is a strong warning that prevents [further] trauma. This analogy defeats its own purpose.
The doctor says, "then don't do that". So, the analogy is correct, and you have missed the point.
I don’t think so. In this analogy you don’t go to the doctor at all, because you feel nothing until a bone cracks. The whole point is based on “but nobody would do that”, so in reality we should see no results of UB and segfaults outside of educational experiments. But the only way to do that is to keep our eyes closed.
>> In the end either safety is either important, or it isn't. Choose accordingly.

Not to disagree with your post but this comes across as very black-and-white.

To expand:

There's a prioritized list of requirements in engineering. Use the right tool for the job.

Rust has: (see https://hackmd.io/@rust-ctcft/r1plN4You#/5 )

1. Safety

If you don't need that at the first slot, then the biggest strength of Rust doesn't apply to your problem (and you would waste time having to track lifetime parameters more than necessary to solve your problem).

There's also another item in that list, and that is performance. As soon as you slightly relax that one, Rust does become massively easier. A well placed .clone() or Arc makes the rest of the code performant enough and easier to understand, which makes the equation of choosing Rust over other alternatives in spaces that aren't necessarily systems programming less problematic.
Arc is equivalent to std::shared_ptr, and so ought to be code smell in Rust.

The .clone() would have been [=] in C++, which would have safely quieted the warning.

Big problem in these discussions is what should be prioritized.

To me, with the 20 years of experience I have in 8 programming languages, I'll always include safety. Especially having in mind that it's nearly zero-cost in terms of runtime performance.

So to me not choosing safety is a strong sign that I don't want to work with the people who practice that.

The point missed everywhere is that Rust lacks key language features needed to capture essential semantics in libraries, that C++ provides. To code libraries I want to code, I cannot use Rust. Rust cannot express them.

So, safety, good, fast enough, good, but insufficiently expressive? No, thank you.

It's probably missed everywhere because I at least have not seen anyone giving concrete info about which are these missing key language features.

Want to elaborate on that? Quite curious.

can you elaborate on those key missing language features ? You have commented multiple times about that, but haven't seen you giving any concrete example. I'm Genuinely curious.
Where to begin? Operator overloading. Programmed move semantics. Generics argument concepts. Look at the whole list of features C++ got since C++11, and subtract out the few of those Rust had or got.