Live data from Hacker News

Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

github.com

111–120 of 174 posts

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#111

Earlier quoted context omitted.

I didn't mean trying to rewrite code to change dynamically allocated objects to stack based ones. That sounds more like an optimization that a managed language like C# might do. C++'s unique_ptr and shared_ptr both have a get() method that will return you a raw pointer to the managed object, which can be a safe optimization within a function holding ownership to the object, as well as allowing you to use legacy funct…

Then I’m afraid I don’t know what your point is. Rust’s borrow-checker isn’t a replacement for shared/unique pointers in C++. It’s a replacement for raw pointers.

My point was that overhead is one common objection to C++'s shared/unique pointers - everything is a method call - but that could be mitigated by the compiler itself doing the type of raw-pointer lowering, when safe, that the get() method permits.

From other replies in this thread is seems that Rust's borrow-checker addresses the high level issues of object ownership and thread safety - it's not just a replacement for raw pointers (i.e. a smart pointer), which is exactly what C++' shared/unique pointers are.

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#112

Earlier quoted context omitted.

Thanks. So basically Rust is combining object ownership and thread safety while C++ keeps thread safety separate, which would seem to provide more flexibility, but also lets you shoot yourself in the foot. Just thinking out loud, I wonder if C++ could better address this by also having a class of thread-aware smart pointers? -- but the problem is that C++ always has the old/new (C, C++) way of doing things - pthreads…

In what ways do you think Rust is not flexible enough? I ask because I can think of a few ways it’s less flexible than C, but I also think that effect is massively overstated by people who aren’t familiar with the language. There are OS kernels written in Rust, for example.

From what I've read it seems that certain types of data structure (incl. anything with potentially circular references) are difficult to write in Rust - you are more fighting the language than it helping you. I'm really comparing to C++ rather than C (where of course anything is possible, as long as you DIY).

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#113
post #62

Earlier quoted context omitted.

Compile time checked pattern matching: https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html

That matches the 'static_assert' portion of my sample code. The implied claim of the parent I replied to was that rust could do this even for runtime values, such as the one I am using in the main of my sample. In c++ it is the same function running both the compile time check and the unchecked runtime variant, so there is zero overhead at runtime. I can't possibly think of a way how rust would be able to make the sa…

You aren't mistaken. I should've written "runtime overhead" - my point is that there is no runtime performance penalty for getting rid of the UB in the Option API.

An equivalent API with no UB is just strictly better.

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#114
post #82

Earlier quoted context omitted.

The point is that Option in Rust doesn't have undefined behavior in any case, even if the values aren't known at compile time. Exhaustiveness is always checked at compile time, unlike C++ where operator* offers an escape hatch where nothing is checked in non-constexpr contexts. "Make everything constexpr" isn't a real solution to UB, in the same way that "make all functions pure" isn't a solution for managing side ef…

You can actually implement the C++ behavior, if you want: unsafe fn super_unwrap (x: Option ) -> T { match x { Some(val) => val, None => unreachable_unchecked!(), } } But defaults matter, and Rust certainly doesn’t make this kind of thing ergonomic (which is a correct decision on the Rust designers’ part).

Yeah, absolutely. My point is that Option itself doesn't give you this API and to make an unsafe version, you have to explicitly write it.

Including UB in easy to misuse places is totally unnecessary and a footgun which really does cause issues in real code.

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#116

Earlier quoted context omitted.

In what ways do you think Rust is not flexible enough? I ask because I can think of a few ways it’s less flexible than C, but I also think that effect is massively overstated by people who aren’t familiar with the language. There are OS kernels written in Rust, for example.

From what I've read it seems that certain types of data structure (incl. anything with potentially circular references) are difficult to write in Rust - you are more fighting the language than it helping you. I'm really comparing to C++ rather than C (where of course anything is possible, as long as you DIY).

Yes, data structures with cyclic references are a bit harder to write in Rust than in C or C++. But it’s not impossible. And IMO, you write those so rarely that it really doesn’t matter.

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#117
post #60

Earlier quoted context omitted.

pub fn expect(self, msg: &str) -> T So that says it's a method (its first parameter is the type itself, but named self rather than as a normal parameter so we can use method syntax instead of calling the function Option::expect) but it also takes an immutable reference to a string slice. That second parameter, msg, is the text for a diagnostic if/ when you're wrong. So, in a sense it's like value() but the diagnostic…

Are there no stack traces? Wouldn’t that point you to where to start trouble shooting?

No, you are not guaranteed a stack trace, in an optimised release build it may not even be possible to construct a valid trace. If you can reproduce the problem you can say you want this run to have a stack trace, but if your release builds just exit immediately on panic then there's no reason for them to be able to provide a stack trace of the fault.

On the other hand expect will provoke the message you wrote if it fails. Of course if it's inside a consumer's fitness tracker it probably doesn't have any way to show the message to a human, but that's a different problem - the fitness tracker presumably can't display stack traces either.

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#118
post #104
post #84

Earlier quoted context omitted.

So ARC is something like the following? template struct Locker { using M = std::shared_mutex; struct Locked { Locked(mtx, value) : m_lock(mtx), m_value(value) {} // operator->, operator*, get, etc. private: std::lock_guard m_lock; std::shared_ptr m_value; }; struct Shared { Shared(mtx, value) : m_lock(mtx), m_value(value) {} // operator->, operator*, get, etc. private: std::shared_lock m_lock; std::shared_ptr m_value…

Rust `Box` = C++ `std::unique_ptr`, both have the same ABI (just pointers) Rust `Arc` = C++ `std::shared_ptr` Rust `Rc` = C++ `std::shared_ptr` but using a simple integer instead of an atomic so it is not thread safe `Arc` and `Rc` do not allow you to mutate their contents directly so instead you should use "interior mutability" using something like a `Mutex` (thread-safe) or `RefCell` (not thread-safe), which have r…

You say:

> Rust `Arc` = C++ `std::shared_ptr`

GP says:

> Rust requires shared pointers (Arc) to also explicitly implement some sort of Mutex-equivalent runtime safety check in order to mutate the data.

Which is it?

> An example of a big C++ codebase using something similar is Chromium ...

Chromium's smart pointers are similar to their standard counterparts -- no mutexes for write access to pointed data.

Also, tangent but interesting: From https://www.chromium.org/developers/smart-pointer-guidelines...:

> Reference-counted objects make it difficult to understand ownership and destruction order, especially when multiple threads are involved. There is almost always another way to design your object hierarchy to avoid refcounting

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#119
post #73

Earlier quoted context omitted.

pub fn expect(self, msg: &str) -> T So that says it's a method (its first parameter is the type itself, but named self rather than as a normal parameter so we can use method syntax instead of calling the function Option::expect) but it also takes an immutable reference to a string slice. That second parameter, msg, is the text for a diagnostic if/ when you're wrong. So, in a sense it's like value() but the diagnostic…

Right, but that's redundant with the stack trace. It's not actually helpful to run a big program I don't know very well and panic with a single "your goose isn't cromulent!" message from a call 20 levels deep. In your example, it's likely that the person who sees this message won't have enough context to understand it; it's more like a debugging assert. Since you'll need a debugger and a breakpoint anyway, the messag…

The nature of expect is that this is a bug. The person who wrote this code was wrong, they expected that this optional has Some value but it does not.

In most cases then, if you don't know this code very well, that's fine because it's not your bug. In the edge case that you just got handed a pile of poorly documented code somebody else wrote, perhaps over several years, well, at least you know what they thought is supposed to happen here and that they're wrong.

And no, I don't find it better to be told "It broke, break out a debugger and try to reproduce the fault". With this text we can revisit the Goose wrangling code and maybe, now that we're staring at it knowing a real customer saw this fault, we are inspired and realise that sometimes it won't find a Goose, then decide what to do about that.

Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20

#120

Earlier quoted context omitted.

There is no implicit conversion (except to bool, but that tells you whether the optional contains a value), and operator* / operator-> throw std::bad_optional_access if it’s empty. See https://en.cppreference.com/w/cpp/utility/optional

You're describing what it would do in a sane world where WG21 cared about safety. In this world, as the document you've linked says: "The behavior is undefined if *this does not contain a value." The operators for such access are actually `noexcept` - the exception you're apparently relying on would be illegal.

Should’ve checked my own link instead of relying on memory — I might have some code to revisit on Monday. That’s insane, thanks for correcting me!
Post reply on HN