Hacker News new | ask | show | jobs
by lionkor 23 days ago
It depends just how fast you need it. C++ is much easier to get to zero abstraction code.

In Rust you are constantly fighting the stdlib and other libraries, and you have to litter your hot code with unsafe blocks to get it to stop adding a branch to nearly every object access, be it for bounds checks or over/underflow checks.

C++ does a much better job at giving you a zero abstraction API, and you can always drop down to raw pointers if you want, without(!!!!) unsafe blocks and weird tricks. Of course it's unsafe in C++ but the friction to writing a branchless hot loop is muuuuch smaller.

When profiling and optimizing Rust code, I very often find myself poring over the generated code, making small changes, reading api docs, and trying again, much more than in C++. Lots of unsafe Rust APIs are not even nearly good enough, even with most checks turned off you will find branches that just branch to panic!(), which is, you guessed it, still more code and a branch than the code would suggest.

I get why people think that most systems languages are the same "speed", but they really are not if you are hitting limits of the hardware in your hot loops.

2 comments

How is not having to mark your unsafe code as unsafe a good thing?

You couldn't have come up with something more incomprehensible.

If 99% of your code doesn't use unsafe, why contaminate 100% of your code base with footguns?

I agree with your point, but for completeness:

> How is not having to mark your unsafe code as unsafe a good thing?

The problem with unsafe code in Rust is that IIRC nobody actually figured out yet the "rules" of unsafe i.e. which invariants you can stretch and which can cause UB. My (not super up to date) understanding is that this is an active area of research and progress is being made and also that in practice there are many well understood usages.

In short unsafe rust is somewhat worse than C++ as the boundaries of UB are less well understood/defined

I don’t know what you’re referring to. Unsafe seems pretty well defined for 99% of use cases. Unsafe blocks allow you to dereference raw pointers and call unsafe functions. Thats about it. Remarkably, even in codebases which need a lot of unsafe (eg the kernel), almost all code is safe code.
What I mean is that unsafe code allows you to eg break std invariants (set invalid length to Vec, unlock a locked mutex, etc.) in ways that can be UB, which of these are UB and which can be used "safely" is sort of unknown.

For better or worse they are much more well understood in C as they are front and center of the language semantics

> over/underflow checks.

Integer overflows are not checked in release builds by default, since they are not related to memory safety.

On the other hand, rust emits noalias everywhere, which helps in autovectorization.

Yep. And array bounds checks have a miniscule performance impact at runtime because they're so friendly to branch prediction.
It depends what kind of hot loop you have.
If you have a hot loop where it matters, you can put an assert outside the loop which lets llvm remove the bounds checks. Or use unsafe { get_unchecked() } to remove the bounds check entirely.
Exactly, yes. I know it's possible, of course it's possible, its just not trivial like it is in C++.

Most developers I have met don't know how to use a profiler, so not sure any of this discussion matters at all anyway, but I feel like it's important to note when the default in Rust is safe, whereas the default in C++ is fast (and more or less unsafe)

Eh, that argument cuts both ways. Lots of the defaults in C++ are bad. Like, most people don’t know how compiling all your code in a single code unit will improve performance. Or how to do it. In rust it’s a single flag in cargo.toml which is widely talked about. Rust has a much better, faster standard library than C++. Any code which makes heavy use of - for example - sorting in C++ and rust will favour rust because it uses a better algorithm by default.

Rust had the opportunity to iterate on C++’s default choices and improve on them in many cases. I’m not convinced that naive C++ is particularly efficient.

(That said, lots of rust beginners make heavy use of Box and clone() and write inefficient programs that way. It’s hard to actually measure average, beginner code.)