Earlier quoted context omitted.
> How else would you implement C++’s vector::operator[] for example? Are you asking in a theoretical world where it isn’t defined to already return a `T&`?
Now that GP said it, it'd be nice to be able to write "some_map[i].value_or(some_value)".
Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
101–110 of 174 posts
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#102Earlier 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.
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…
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#103Earlier quoted context omitted.
> How else would you implement C++’s vector::operator[] for example? Are you asking in a theoretical world where it isn’t defined to already return a `T&`?
No, that’s my point. It returns a reference. So it’s a good example of when you might want to return a reference, which you said seemed uncommon. But the reference it returns is unsafe (for example, it gets invalidated if the vector is later resized), whereas the reference returned by the corresponding Rust operator is safe.
My overall advice here would be that if you find yourself implementing vector-like data structures very often, then it is time to take a second look the design.
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#104Earlier quoted context omitted.
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 ar…
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 `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 runtime checks to ensure no undefined behaviour is introduced. So `Arc>` makes it possible to mutate `T`, but `Arc` cannot. Some types like atomics do not require mutability at all, so an `Arc` can be mutated directly.
An example of a big C++ codebase using something similar is Chromium, where `std::shared_ptr` is forbidden and `base::RefCounted` (Rust `Rc`) and `base::RefCountedThreadSafe` (Rust `Arc`) should be used instead. WebKit does this too.
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#105Earlier quoted context omitted.
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.
I'm pretty sure you could embed a language with lifetimes in a dsl built with c++ templates. You wouldn't want to use it beyond toy programs though.
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#106This 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?
Interesting, why is this? I would have assumed the compiler could have optimized away that indirection.
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#107Earlier quoted context omitted.
No, that’s my point. It returns a reference. So it’s a good example of when you might want to return a reference, which you said seemed uncommon. But the reference it returns is unsafe (for example, it gets invalidated if the vector is later resized), whereas the reference returned by the corresponding Rust operator is safe.
Sure, but the person I was relying to said they were writing code that returns references (not implementing the standard library). And my surprise was that they have to do it so often. My overall advice here would be that if you find yourself implementing vector-like data structures very often, then it is time to take a second look the design.
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#108Earlier 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…
This is not actually true, but it's close enough for your purposes here.
But just to be clear about it, see stuff like this: https://stackoverflow.com/questions/58339165/why-can-a-t-be-...
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#109Earlier quoted context omitted.
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 ar…
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…
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.
Re: Rusty.hpp: A Borrow Checker and Memory Ownership System for C++20
#110Earlier quoted context omitted.
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 ar…
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…