Live data from Hacker News

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

github.com

71–80 of 174 posts

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

#71
post #66

Earlier quoted context omitted.

Rust has unique and shared pointers too (Box and Arc/Rc). But using them when unnecessary results in extra heap allocations. I’m not aware of C++ compiler that can consistently rewrite uses of unique_ptr to heap-allocated objects to use raw pointers to stack-allocated objects instead.

Theres nothing special about unique_ptr, if you dont want allocations and youre ok with just moving your values around directly, you use value and move semantics.

Move and value (deep copy) semantics exist in Rust too, but neither of those does the same thing as passing a raw pointer (or reference). Which you can do in c++, but not safely. That’s the difference with Rust.

In C or C++ if a function/method takes a raw pointer (or some other lifetime-constrained type like string_view), I have no idea if it’s going to stash it somewhere and try to look at it again later. If it returns a raw pointer or reference, I don’t know whether it is going to get invalidated by some future call. Iterator invalidation is a huge source of UB in C++ but completely unknown in rust.

Clearly having a hash map where all the values are stored indirectly in shared_ptr would let you provide a safe access API, but would be horrible for performance. In Rust you can have the safe API without compromising on efficiency.

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

#72
post #62

Earlier quoted context omitted.

can you show me how rust does this? I'm genuinely curious. I've made a toy example to show how c++ checks for undefined behavior at compile time, I am unaware of rust being able to do the same without runtime costs (however small they may be, this is a toy example after all) https://godbolt.org/z/cT9bqz8z7

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 same code in my sample safe without adding runtime checks. If I am mistaken here I sure would like to know.

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

#73
post #38

Earlier quoted context omitted.

> The Option type seems to have various standard Rust methods like expect() Isn't that value()?

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 message isn't very helpful.

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

#74
post #14

Earlier quoted context omitted.

I don't see any way to express something like Option in C++ Regardless of "age of the project" or other considerations, this doesn't seem like a particularly tricky edge case of generic programming and yet C++ is stumped AFAICT

According[0] to Perplexity.ai, you could use std::optional to get a C++ approximation of your Rust type. I am neither an expert in modern C++ nor in Rust, but I have witnessed enough of C++'s evolution over time to know that if C++ language devs find a feature desirable enough they will do whatever it takes to frobnicate the language in order to claim support for that feature. [0] https://www.perplexity.ai/search/is-…

std::monostate is a "unit type"[1]; there's only one value with with type monostate (the value is std::monostate{}), so all monostate values are equivalent.

Infalible is a "empty type"[2]; there are no values with type Infalible, so a value cannot be constructed, so Optional is always None, never Some(infallible). Importantly, the compiler knows this and can use it to reason about the correctness of code.

C++ has no empty types. Void is close, but it's sometimes used where a unit type would be used, and anyway it's not a first class type. For example, you can't use std::optional. Even if it were possible to make an empty type in C++, it wouldn't give you anything, because the compiler isn't equipped to reason about them.

BTW, the rust equivalent to std::optional is Optional. The empty tuple is Rust's idomatic unit type.

[1]: https://en.wikipedia.org/wiki/Unit_type

[2]: https://en.wikipedia.org/wiki/Empty_type

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

#75

Can someone familiar with both please explain the benefit of Rust's borrow checker memory management model over C++'s std::unique_ptr and shared_ptr ? Is there some safety argument to prefer Rust's model, or is it something else ? I'm not aware of any C++ compiler doing it, but it seems smart pointer overhead could be automatically and safely reduced (in same way one can do it manually) by the compiler lowering the g…

The C++ smart pointers dont prevent multiple threads from mutating the pointed-to data at the same time; multiple threads can both access a unique_ptr at the same time and mutate its contents. Rust requires shared pointers (Arc) to also explicitly implement some sort of Mutex-equivalent runtime safety check in order to mutate the data. Rust also has explicit notion of thread ownership, and whether individual types are safe to pass to different threads; if a construct is not thread safe, Rust will prevent you from using it in multiple threads.

As a benefit of the thread-safety notion, Rust can have two reference-counting pointer types: Arc, which uses atomic reference counting and is roughly equivalent to std::shared_ptr, and Rc which does not use atomics. Rc cannot be used across multiple threads at the same time, and the borrow checker will prevent you from doing this.

Rc is appropriate for data structures which internally benefit from multiple pointers (e.g. graphs) but where all of that information is internal to a single data structure - this becomes available without paying the price of atomics.

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

#76

This borrow checker runs at runtime, which I find not as interesting. Everything starts to look a lot like std::unique_ptr which I think is mostly unneeded as it ads pointer indirection. Could someone explain to me when one would use this? Is it for educational purposes perhaps?

I don't think it is intended to be used in a real system, this was more of an experiment to see what was possible. C++ as a language isn't well-suited to supporting a compile-time borrow checker. The difficulty of retrofitting C++20 modules to the language is probably just a glimmer of the pain that would be involved in making a borrow checker work.

There is a place for runtime borrow checking. Some safe cases in well-designed code are intrinsically un-checkable at compile-time. C++ is pretty amenable to addressing these cases using the type system to dynamically guarantee that references through a unique_ptr-like object are safe at the point of dereference. Much of what the borrow checker does at compile-time could potentially be done at runtime with the caveat that it has an overhead.

This has more than a passing resemblance to how deadlock-free locking systems work. They don't actually prevent the possibility of deadlocks, as that may not be feasible, but they can detect deadlock conditions and automatically edit/repair the execution graph to eliminate the deadlock instance. If a deadlock occurs in a database and no one notices, did it really happen?

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

#77
post #51

Earlier quoted context omitted.

> pretty complicated(possibly impossible) Rust does it at compile time, so why cant C++? to me this detail completely kills the usefulness of this project

C++ cannot because it does not have the necessary information present in its syntax. It’s really that simple. C++ could add such syntax, but outside of what Circle is doing, I’m not aware of any real proposal to add it. Also, Google (more specifically, the Chrome folks) tried to make it work via templates, but found that it was not possible. There’s a limit to template magic, even.

Although it's not as extensive as Rust's lifetime management, Nim manages to infer lifetimes without specific syntax, so is it really a syntax issue? As you say, though, C++ template magic definitely has its limits.

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

#78

Can someone familiar with both please explain the benefit of Rust's borrow checker memory management model over C++'s std::unique_ptr and shared_ptr ? Is there some safety argument to prefer Rust's model, or is it something else ? I'm not aware of any C++ compiler doing it, but it seems smart pointer overhead could be automatically and safely reduced (in same way one can do it manually) by the compiler lowering the g…

Read this: https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/ It will help you understand why "smart pointers" still won't help you.

I read that more as a valid criticism of other parts of C++ rather than about smart pointers as a way to track ownership.

e.g. std::string_view seems broken by design in wanting to support both raw-pointer based strings with zero ownership semantics as well as std::string. A string view (abstract concept) really needs to either have shared ownership of the underlying string, or have a non-owning reference that knows when it has been invalidated.

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

#79

The C++ type system is completely inadequate for these tasks. I thought of a rather nice way to picture it, the C++ type system is like you have Roman Numerals, and so now the notation itself fights trying to understand important concepts about numbers (types). Languages with a better type system are like having Arabic Numerals, it's not a panacea, but the notation allows significant improvements in expressiveness an…

Current version of C++ can handle empty and zero-size types quite well, though you are correct that older versions of C++ had limited support (and non-existent pre-C++11). I create and use them regularly when metaprogramming.

The bigger issue is that all of this new capability can't be easily grafted onto the old standard library. If you were to write a re-designed standard library from a C++20 baseline, and some people do, it is a dramatically different experience. Modern C++ is an amazing library-building language but the 'std' library it comes with is legacy rubbish in many regards.

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

#80
post #30

Earlier quoted context omitted.

The lack of support for optional is not an issue at all in my opinion. The actual issue is that std::optional is not a monadic type in the vein of Rust's Option or Haskell's Maybe. So really, what does it buy you over std::pair ? Except being unsafe by default since it allows you to access an unconstructed T. Basic monadic operations don't arrive for std::optional until C++23, which is an unforced error. They should…

Funny how this just keeps happening in the C++ world. I've seen ten different promise/task frameworks successfully used in production with neat APIs but somehow std::future is still just a toy. Even std::expected was released without the usual map/then.

[deleted]
Post reply on HN