@GlowingLantern Such absolutist view makes the problem impossible almost by definition, so it's completely impractical.
Every lock can be picked, so is there no point having doors? If a door can't be guaranteed to be really locked, why upgrade from a piece of string to a steel padlock?
@kornel your argument is the absolutist one in terms of the language. Asking how to make C++ absolutely safe in regard to object lifetime management, one arrives at rust as the answer. Except then one realizes that nothing is absolute and the language is fundamentally flawed without the unsafe code, that is there are efficient and safe data structures that are impossible to implement with the hard requirement of absolute language level safety.
C++ could easily have a subset, sticking to which you can have exact same guarantees. At that point it just becomes a question of opt-in versus opt-out. I imagine when it gets to it, we'll also know a lot more about object lifetime management, and employ better abstractions and customization points.
@GlowingLantern@misskey.de
@kornel I can only see that being true from the point of view of applying the model to absolutely everything across the board. You want raw references or pointers to be borrowing, c++ says nope of course. You want a special borrowing reference? Nothing compatibility or ABI breaking there. It's just a matter of defining good fundamental abstraction in the language standard. Yes C++ will never have rust's model, it will more likely have a few new fundamental building blocks added with which you could implement rust's model as a library, and many other similar models.
@namark "it will more likely have a few new fundamental building blocks added with which you could implement rust's model as a library"
Google literally tried to implement that:
They've identified big obstacles to implementing this, including need for a different type of moves and destructors. Not as easy as new building blocks, because it touches so much of the type system and has complex semantics. They recommend adding borrowing built-in into the compiler.
@namark I recommend checking Rust's history of the borrow checker, from being scope-based (close too what could be done with a metaprogramming library), to being IR-based AKA "NLL", to Polonius project which tracks regions on control flow graph. Borrow checking is way harder than it seems. Even relatively simple code runs into issues that are either soundness holes, or become freakishly complex to prove.
@namark And given that borrow checking has tricky cases that are either unsafe or require writing a subset of a prolog compiler inside your C++ compiler to solve, I expect C++ WG to choose holes every time.
They've failed even in easy cases. They could have made std::optional UB-free, but chose not to. They could have added pattern matching or ADT instead of std::variant contraption, but chose not to. C++ could have been copying Rust's safety for 2 releases now, but went with old habits instead
@kornel I guess I'm a heretic, but to me the UB of optional is a feature, and I don't see variant as a standing for pattern matching, to me it was primarily presented as an alternative to traditional dynamic polymorphism, where you would naturally restrict yourself to common denominator interface, not branch on different interfaces.
You seem to overestimate the scope of features in c++. They are usually rather narrow and focused, with a purpose to get a certain specific thing right, not chase the latest fads in programming.
@namark ADTs are from 1970s, hardly a latest fad. They turned out to be a very useful language primitive that made several special-case features unnecessary.
Both C++ and Rust are 100% safe when the programmer writes correct code. The thing I don't see in C++ community, is accepting that programmers will write bugs and use things incorrectly. 40 years of complaining at bad and lazy programmers haven't worked.
std::optional is unsafe when used incorrectly. Option is safe when used incorrectly.
@namark Rust's approach is safety first, and optimize out unnecessary checks second.
I can't imagine C++ adding checks to [] or even major codebases banning it. Rust's [] throws on out-of-bounds access.
This isn't as much of a technical difference, as it is in ergonomics and the "happy path" presented to the lazy programmer. C++ users are very often opposed to catering to bad programmers, opposed to any runtime cost. C++ will not catch up in safety with that mindset.
@kornel since when is ADT and pattern matching the same thing?
And oh yes of course let's use it wrong and still make it work. Lets design a drill that is monkey proof and apply it across the board wherever any holes need drilling. It's actually an single exoskeleton that doesn't fit most applications but we have change the world to make it fit.
That philosophy is flawed (yet surprisingly common), it presumes the language developers are better than anybody else and found the holy grail of programming. Many such holy grails had come and went. In time the hordes of illiterate apes whose incoherent scribbles rust is so desperately trying to contain will come up with superior programming patterns that it never even anticipated and completely deprecate it.
C++'s philosophy is to respect its userbase.
@namark In Rust pattern matching is the "UI" for ADTs, so they go hand in hand. Pattern matching is a fad from 1957.
Your triade about apes/scribbles/grails/wtf is just empty emotional posturing.
The data is that the respected C++ userbase keeps writing memory bugs. GOOG and MSFT (who are not amateur coders) report ~70% security issues due to it.
Rust eliminates majority of them, most by construction. Makes real-world difference, e.g.: https://github.com/rust-fuzz/trophy-case (panic/unwrap == C++ exception)
@namark The fact that you take existence of language constructs and APIs that are impossible to use incorrectly as a disrespect and personal offence is what I typically see from C++ users. This is why I don't believe C++ will catch up in safety with Rust, because there's no will to do it. It's always just a blame on "bad programmers" instead of having a hard look at the language that keeps enabling this.
Rust blames itself for bugs, and strives to help "bad" programmers make reliable software.
@kornel personal offense? I guess I have to chew it up for you after all. I don't take a personal offense, my point was that i don't believe that language developers are better at programming than the entire userbase of the language. But I guess you are too emotional to read through the flare.
@namark If you look at e.g. Chrome team, it's not "regex replace". It's a project that from the start has been focused on security and is leading in the field. If such high-profile well-funded project like Chrome can't find engineers that are good enough to write "good" C++, then it's only going to be worse for everyone else.
The "cesspools of snake oil" is an empty rant. You've brought the discussion level to slinging insults. This is not something that can be productively discussed, so bye.
@kornel You keep bringing up project that are notorious for being poorly designed from the language lawer's perspective, and try to present them as some kind of quality standard. If you can tell me how big of an issue memory errors are in C++ standard library implementations for example I might be convinced you know?
Obviously "regex replace" was an exaggeration, the point is, Chrome for one, is a huge unmaintainable monolith, as in not modular, and they are constantly looking for ways to automatically fix/inprove it somehow, through changes in the language and tooling, because hard to impossible to do it otherwise.
And what do you mean by insult? Who's person did I attack? Or did you mean I insulted a codebase? Unacceptable.
I actually used snakeoil specifically in reference to the state of the industry that is largely run on pop culture and marketing alone, without fair competition or any quality standards, but sure it's just an empty rant.
@kornel There were no programming fads in 1957, you need pop culture to have fads.
I critique your philosophy with a bit of flare.
Tou dismiss it as emotional posturing.
It's Super Effective!
GOOG and MSFT, of course, as a practitioner of the discipline I have much respect for these cesspools of snake oil. It's not like they accumulate all the bad practices over the years in giant indivisible monoliths, and then try to find ways to regex replace some stings in them to fix all the problems, which would explain the mindset in the writeups you linked here.
You will make a real world difference when you implement a system of same complexity and objectively proove it more stable and otherwise equivalent, not by counting all 0 memory errors in a language that was designed to eliminate memory errors. And then on top of that somehow prove that a similar thing can not be achieved with same effort re-implementation in modern C++. Until then it's not a real-world difference, it's marketing.
@kornel took a cursory glance and it seems all backwards to me. They are trying to wedge in a borrow checker into c++ move semantics, that immediately smells to me as a dead end. It again seems to me as this weird fixation, like they have rust as a premise and try really hard to sell it. What they want is to be able write some safe code, and then unleash the spaghetti monster on it and make sure it can't introduce memory errors. What a noble goal it is.
Instead to understand what I have in mind you have to ask "can I have a library, the invariant of which, given that I don't break it on my side, is equivalent for most intents and purposes to the borrow checker". You shouldn't use std::move and try to design try to change the whole language to allow borrow checking. Whatever move function you use (be it separate or a overload of std::move) it should not get a lvalue reference and return a rvalue reference, it should deal with special types, that don't have the necessary lifetimes according to language definition, but emulate the necessary lifetimes. The immediate hurdle you run into then is lack of mutable compile type counter, by just adding that, you can already do a lot as a library. Template meta-programming a subset of prolog? Yes please!
And yes the borrow checker is way harder than rust developers thought it was, it has a lot more gray areas and tradeoffs to make, I would prefer a library of primitives that would allow me to make the all the meaningful choices there are to make.
@namark The things they're implementing aren't simply "because Rust does it". If you choose shared XOR mutable aliasing model for references, there are logical consequences of it.
I think you're severely underestimating complexity of the problem, and your approach wouldn't be sound, nor ergonomic when interacting with rest of C++.
Rust has UnsafeCell type to allow library primitives to "break" its aliasing model (this powers atomics, refcells, mutexes).
@namark Such options were explored and some even prototyped in the doc I've linked to at the beginning.
Borrowing model needs different move and dtor semantics. You'd have to have two kinds of incompatible refs, and two kinds of incompatible dtors. It'd fragment C++ codebases. This may be doable technically, but not politically.
That's why Google chose to bet on MiraclePtr (a garbage collected pointer, essentially) instead of single-ownership and borrowing model.