Live data from Hacker News

Safety: A comparaison between Rust, C++ and Go

nested.substack.com

101–110 of 188 posts

Re: Safety: A comparaison between Rust, C++ and Go

#102

Earlier quoted context omitted.

Oh I completely agree that defaults matter, and I wouldn't advise anyone to go start some big C++ project unless they had a very good reason to. But Rust vs. C++ is not an apples-to-apples comparison in this regard: Rust got a clean slate and was willing to cut ties with engineer-millenia of existing high-value software to do it. In a perfect world Rust wouldn't be ambivalent at best and hostile at worst to C++ inter…

Rust isn't hostile about C++ interop, it's that between native interop (which requires dealing with templates and memory unsafety) and safety, Rust prioritized safety, while Carbon is trying the alternate approach. The behavior of C++ is simply hard to interface with while providing the assurances Rust gives you. Edit: how many languages have native C++ interop that supports the whole language? Would love to hear of…

It's not just C++ interop. We chose Zig because writing C library bindings for Rust is bewildering.

Re: Safety: A comparaison between Rust, C++ and Go

#103
post #70

Earlier quoted context omitted.

I dunno man. I've done C, C++, JavaScript and TypeScript professionally for significant chunks of my career, and the trend that I've observed has overwhelmingly been towards stricter compilers. For example in the front-end world, TypeScript has absolutely exploded in adoption. Everyone could be still using JavaScript, but companies from startups to huge corporates have explicitly decided they want compile type safety…

Oh I think we probably see largely eye-to-eye. My weapon of choice when there are no other constraints is Haskell, and one reason I really like Rust is that I can get a lot of the Haskell features I like in a highly-performant setting. Most of the C++ I maintain these days is in whole or in part generated by Haskell. And if I have to write something fast by hand and it doesn't need to link to stuff I need, I reach fo…

> Most of the C++ I maintain these days is in whole or in part generated by Haskell

Can you expand on that? I'm currently researching something similar but lower level & lisp instead of Haskell. It would help to see some existing examples to figure out if it's worth it or not.

Re: Safety: A comparaison between Rust, C++ and Go

#104

Earlier quoted context omitted.

I find it so weird that the Rust community is borderline evangelical about memory safety when a) it's not actually memory safe once you start doing heavy shit b) modern C++ is quite memory safe and c) there are so many other great reasons to like Rust. Memory safety in serious systems software is something that you approach asymptotically and/or probabilistically. Rust makes it easier to be memory safe in a lot of sc…

> a crashed program is a crashed program whether I dereferenced a null pointer or was poking around in a slice with multi-byte Unicode characters in it They aren't the same thing though, that's the point. Dereferencing a NULL pointer isn't guaranteed to crash. In fact if you are writing through the pointer, you may even have a security issue on your hands (rce, etc). Safe Rust may have runtime errors that "crash" the…

Yep, my favorite part of heap/stack corruption is not when it crashes immediately but rather when it rears its head 2-3 weeks/months later when some upstream call pattern or timing has changed.

I've spend weeks chasing down single instances of this on multiple projects. The nasty part is you have no predictability in if it's going to be one that crashes immediately, silently writes garbage(hopefully not to disk!), is a latent lurking crash or security vuln.

If you trash the stack then there's a good chance you lose the backtrace as well which can make a hard to debug issue become "find the needle in the haystack". I hope it's something that reproduces quickly and consistently because otherwise you're in for a ride.

Re: Safety: A comparaison between Rust, C++ and Go

#105
post #97

This would be a better article if the UB in the C++ example wasn't blindingly obvious-- no C++ programmer worth a damn would ever write this.

Why is this such a common defense for the peculiarities of C++? I see it pop up at least a couple of times, anytime C++ is criticized. I don't have anything against taking pride in one's skill and craftsmanship, but excusing a tool's failings purely on the basis that one needs more skill to wield it and avoid those failings? I want to have that same level of skill and have my tool multiply my skill's output to the ma…

Because the code in question isn't something a C++ dev would write, instead it looks like something someone who doesn't use the language much if at all, decided to use for this pretty silly comparison.

It would be one thing if this required skill, but this example is downright silly. Some other people here have posted more reasonable version, that might actually occur in the real world(like the example with std::span)

Re: Safety: A comparaison between Rust, C++ and Go

#106
post #54

Earlier quoted context omitted.

Rust's thread safety only applies to the special case of those threads accessing in process data segments. Rust's type system can do very little to help when those threads are accessing the same record on a database without transactions, OS IPC on shared memory, manipulating files without locks, handling hardware signals, handling duplicate RPC calls,... Yeah but that ultimately requires an unsafe block, kind of true…

This has been a recurring theme from you, but in the cases you're describing the risk is only a race condition (no general solution is possible) and not a data race (which safe Rust is able to deny by design). These are categorically different problems.

Because it is a recurring theme to ignore the other kind of race scenarios when promoting Rust's type system.

Re: Safety: A comparaison between Rust, C++ and Go

#107
post #54

Earlier quoted context omitted.

Rust's thread safety only applies to the special case of those threads accessing in process data segments. Rust's type system can do very little to help when those threads are accessing the same record on a database without transactions, OS IPC on shared memory, manipulating files without locks, handling hardware signals, handling duplicate RPC calls,... Yeah but that ultimately requires an unsafe block, kind of true…

This is a point that you constantly bring up in these threads, do you think most developers believe that data race safety should extend beyond the bounds of the process? One thing that Rust’s type system does allow you to do is define a consistent manner in which to access external systems, even add types that will mimic the same safety. Is it perfect? Will it protect you from a different process working against the…

Yes, when they care about data consistency in distributed systems.

Maybe many Rust devs don't care.

Re: Safety: A comparaison between Rust, C++ and Go

#108
post #84

Earlier quoted context omitted.

> In C++ the community "default" is `absl::flat_hash_map`/`folly::F14`, which use SIMD to compare a whole stripe of key-prefixes simultaneously. Just to be clear, the Rust HashMap does the same thing.

TIL. Thanks for letting me know that: https://doc.rust-lang.org/src/std/collections/hash/map.rs.ht... I don't know how I missed this, is the Swiss port a fairly recent development?

Hashbrown (the Swiss Tables implementation) replaced the previous HashMap implementation in July 2019.

The port is a little older, 2018. The idea was famously explained at CppCon 2017, I don't know whether Google had published on Swiss Tables before that year.

Re: Safety: A comparaison between Rust, C++ and Go

#109
post #27

Earlier quoted context omitted.

>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…

> 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…

> 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.

Re: Safety: A comparaison between Rust, C++ and Go

#110
post #11

Disingenuous. 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. It is not, then, a closure at all. Using a correctly-defined make_appender would not, then, produce undefined behavior when you use it, with or without "move". What the author has done here was to take a too-…

You can add [[clang::lifetimebound]] on the suffix parameter and you get :21:35: warning: temporary whose address is used as value of local variable 'append34' will be destroyed at the end of the full-expression [-Wdangling] auto append34 = make_appender({3, 4});

You dont need annotations, cppcheck already warns with:

    test.cpp:16:45: error: Using object that is a temporary. [danglingTemporaryLifetime]
        assert((std::vector{1, 2, 3, 4} == append34({1, 2}))); // FAIL: UB
                                                ^
    test.cpp:3:12: note: Return lambda.
        return [&](std::vector&& items) {
               ^
    test.cpp:2:50: note: Passed to reference.
    auto make_appender(std::vector const& suffix) {
                                                     ^
    test.cpp:4:36: note: Lambda captures variable by reference here.
            return append(move(items), suffix);
                                       ^
    test.cpp:15:35: note: Passed to 'make_appender'.
        auto append34 = make_appender({3, 4});
                                      ^
    test.cpp:15:35: note: Temporary created here.
        auto append34 = make_appender({3, 4});
                                      ^
    test.cpp:16:45: note: Using object that is a temporary.
        assert((std::vector{1, 2, 3, 4} == append34({1, 2}))); // FAIL: UB
Post reply on HN