←back to thread

177 points signa11 | 2 comments | | HN request time: 0s | source
Show context
Arch-TK ◴[] No.42160944[source]
I have memorised the UB rules for C. Or rather, more accurately, I have memorised the subset of UB rules I need to memorise to be productive in the language and am very strict in sticking to only writing code which I know is well defined (and know my way around the C standard at a level where any obscure code I sometimes need to write can be verified to be well defined without too much hassle). I think Rust may be difficult But, if I forget something, or make a mistake, I'm screwed. Yes there's ubsan, there's tests, but ubsan and tests aren't guaranteed to work when ub is involved.

This is why I call C a minefield.

On that note, C++ has such an explosion of UB that I don't generally believe anyone who claims to know C++ because it seems to me to be almost infeasible to both learn all the rules, or at least the subset required to be productive, and then to write/modify code without getting lost.

With rust, the amount of rules I need to learn to understand rust's borrow checker is about the same or even less. And if I forget the rules, the borrow checker is there to back me up.

I still think that unless you need the performance, you should use a higher level language which hides this from you. It's genuinely easier to think about.

That being said, writing correct rust which is going to a: work as I intended and b: not have UB is much less mentally taxing, even when I have to reach for unsafe.

If you find it more taxing than writing C or C++ it's probably either because you haven't internalised the rules of the borrow checker, or because your C or C++ are riddled with various kinds of serious issues.

replies(7): >>42161052 #>>42161225 #>>42161510 #>>42162166 #>>42162494 #>>42162555 #>>42162621 #
blub ◴[] No.42162494[source]
I think you’re missing the author’s point, but OTOH he undermined it himself by stating that learning the rules helps: because Rust requires that the ownership and relationships are encoded in the type system, it requires significant design changes when those relationships change.

Learning the rules only partly mitigates this, because sometimes one does exploratory programming and isn’t sure what the final types are or they just want to change something.

Rust thrives on over-specification which calcifies the APIs.

Anyway, just as the author’s allegedly holding Rust wrong, one could say that you’re holding C++ wrong - the right approach is to learn how to write correct code and then the exceptions. Also accept and be at peace with the fact that your code will have some bugs. I don’t know why the average Rust developer is so obsessed with getting things perfect and no less with memory safety when the overall software quality is the way it is. I mean if someone’s researching the topic or works on Rust, sure, be the Stallman of memory correctness.

replies(1): >>42164159 #
Arch-TK ◴[] No.42164159[source]
I think unless your code is guaranteed to never interact with any untrusted input it is nowadays an increasingly unacceptable compromise to just accept that your program might have serious flaws which can lead to remote code execution or worse.

Moreover, it becomes increasingly unpleasant and unworkable to deal with code which progressively gets more and more unreliable.

It's expected that if the complexity of a program grows, the state space that the program can occupy grows with it. But with UB you can run into by accident that state space seems to grow exponentially in comparison to a language like Rust.

If you are required to write code at that low level, I would not use anything other than something like rust.

If you are not required to write code at that level. There are many languages with much less uncertainty than C++ which are much more productive than either C++ or rust.

replies(1): >>42166957 #
1. sfink ◴[] No.42166957[source]
> I think unless your code is guaranteed to never interact with any untrusted input it is nowadays an increasingly unacceptable compromise to just accept that your program might have serious flaws which can lead to remote code execution or worse.

I think that's too strong a statement, because it applies to in-development programs. I agree with you if you're talking about released programs, but there can be benefit in leaving open the possibility of detectable flaws, serious or otherwise, while your code is still in development.

It's analogous to only compiling and running in debug mode throughout your development, and then switching to release mode for the final binary. The binary is suboptimal throughout your development process; it's too slow. But as long as the `--release` flag doesn't require any code changes, it's still a better idea than developing entirely in release mode.

Similarly, the binary could be suboptimal from a correctness standpoint, as long as removing the `--devel` flag only works when the compiler is fully happy. `--devel` could turn some borrow checking failures into warnings and still give you a runnable binary. Or it could allow leaving types underspecified in interfaces, and do an unsound type inference. Best case, it could even do runtime checks and/or coercions to establish the assumptions that the callee was compiled with.

Whether it would be worth the complexity is an open question, but it seems reasonably clear that Rust has a problem with brittleness to development-time change.

replies(1): >>42168913 #
2. Arch-TK ◴[] No.42168913[source]
If you develop C or C++ haphazardly in such a way that you leave a bunch of UB on the table during development then there's little to no chance that you'll have actually erased all presence of it by the end of development.

There currently exist no tools which with complete reliability point out all UB in your program. If any part of your program can have UB and you didn't write it with the explicit intention of not having UB in it at any point then you're going to be left with a tough situation to deal with.

I've read a lot of C in my time and there's codebases which I read and find easy and quick to review because they stick to the rules and only bend them sparingly and then there's codebases which are a pain to evaluate even the most basic parts for errors and UB.

There's no such thing as "detectable UB", there's only UB which your tools have luckily managed to detect.

Leave the UB to the people who can't avoid it, stick to safe languages when you can.