Curious why you think using const functions doesn't prevent data races after watching
at 29:00 he says the C++ standard guarantees const member functions are data race free.
Curious why you think using const functions doesn't prevent data races after watching
at 29:00 he says the C++ standard guarantees const member functions are data race free.
What I meant was something like "const itself is not a panacea against data races generally." It is a useful tool.
But in C++ if you have a const member function F() then F() can only change member variables that use the "mutable" key word.
If you default to all methods are const you have much much safer C++. As safe as rust? not probably but combined with liftimes proposal and static analysis rules we have a language good engineers can sufficiently work with.
struct Foo
{
mutable auto a = 4;
auto increment() const -> void
{
this->++a;
}
};
If we train engineers to use const member functions, then the programmer is forced to think about state and mutation.As C++98 PTSD begins to fade and C++17 becomes the cultural mental image of the language, the argument for switching to rust will become less and less compelling.
Eventually, the only "advantage" will be ML influenced syntax.
The reason is there are only three languages that can easily call into C++ code. Objective-C (swift by proxy), D, and of course C++.
Why rust didn't prioritize compatibility with C++ like C++ did with C boggles my mind. Why do you think C++ became so popular? Near perfect C compatibility (until recently) is literally the only reason. Instead of focusing on pragmatisim Rust focused on language purity.
At what cost?
This is not nearly enough. See the examples I gave in my other post.
Besides, all "const" means is "I won't mutate 'this'". It doesn't mean someone else who has a non-const reference to your object won't mutate your object. That makes it largely useless for reasoning at a local level.
> If we train engineers to use const member functions, then the programmer is forced to think about state and mutation.
The programmer may think about it, but the compiler doesn't enforce it at all.
> As C++98 PTSD begins to fade and C++17 becomes the cultural mental image of the language, the argument for switching to rust will become less and less compelling.
Only if you don't understand how Rust works.
> Why rust didn't prioritize compatibility with C++ like C++ did with C boggles my mind.
Because C++ compatibility is impossible without being a derivative of C++, and C++ is hopeless in the safety department. I believe it is impossible to make C++ memory safe without making it not C++ anymore.
> Instead of focusing on pragmatisim Rust focused on language purity.
No, Rust focused on what is possible.
Do you consider D to be a derivative of C++? I don't. They have a near perfect C++ interface. D can even catch C++ exceptions. It's pretty sweet. You can hear about the black magic Andrei used to get that to work here:
http://cppcast.com/2015/10/andrei-alexandrescu/
Side note: I'm actually thinking the Rust and C++ comparison misses the mark. First of all, C++ cannot be obsoleted by rust, it's economically impossible. Secondly, I don't even think they compete in the same domain space. Rust is actually lower level than C++, in that it does lower level stuff in a more natural way. It's C, that Rust makes obsolete; which is something C++ totally failed to do (because of it's RTTI, exceptions, and other runtime features -- all things you and the rest of the Rust team intelligently scrapped). After trying embedded Rust, I'm completely done using C (and the C parts of C++).
IMO the advantages C++ still has over Rust are:
- libraries, libraries, libraries
- C++ has so many great libraries
- *writing* C++ libraries with SFINAE sugar is the bees knees.
- much better support and tooling, but this is for sure a temporary advantage.- template meta-programming feels like a different language, it's dynamic, functional, and the difference is refreshing. I like the mental switch you have to do to go from writing a C++ template to writing a C++ model.
- as much as header files suck, they let you skim an API much more easily than Rust or Swift.
- performant, memory safe data structures:
For example, it's trivial to write a low overhead pointer that can't dangle, throws an exception on nullptr deference, and that safely points to an object it doesn't own (even if that object is its owner). With this and a unique_ptr composed with similar safety mechanisms you now have the primitives needed to write any data structures or algorithm so that it is protected from undefined and unsafe behavior, yet remains performant. This solution has significantly less overhead than using reference counted pointers like shared_ptr derivatives or Rc. The performance tradeoff over using raw pointers is minuscule and totally dwarfed by the gain in safety guarantees. From what I've observed, you can't do this in Rust, if you try to write a doubly linked list you either have to use C-pointers that can dangle inside unsafe blocks, or eat the Rc overhead.
EDIT: How could I forget to mention the glory that is constexpr?
Advantages of Rust over C++ (again, IMO):
- the correct defaults (aka opposite of C's insanity)
- best C++11 features built in and defaulted (move semantics, unique_ptr is Box<T>, Rc is shared_ptr etc..)
- Bad ass embedded capabilities. You don't nearly feel as crippled like you do in C++ without the STL.
- the safety guarantees are real, and they're awesome
- move semantics into closures looks so goddamn elegant. I love it
- inline assembly doesn't feel like a hack
- modules and cargo rock
- secretly and surprisingly similar to ruby in a lot of places :)
- it wants you to think functionally, and unlike Swift, it means it. This is a good thing.
Just to reply to this individual point, rustdoc is fantastic. Personally I much prefer having an HTML-rendered "header file" for a crate's API. Even if they aren't hosted, it's trivial to generate one yourself using `cargo doc`. To be maximally useful, the author needs to have made doc comments, but at least there's a standard format for that, and you might not have anything like that in a header file anyways.
It's not a near-perfect C++ interface, because D can't instantiate C++ templates on its own.
> First of all, C++ cannot be obsoleted by rust, it's economically impossible.
Rust can make C++ obsolete in a technical sense. But I agree of course that C++ is immortal.
> For example, it's trivial to write a low overhead pointer that can't dangle, throws an exception on nullptr deference, and that safely points to an object it doesn't own (even if that object is its owner)
Wrong. You can't write a pointer that can't dangle in C++. Think iterator invalidation, "this" invalidation, etc. I've given innumerable code samples to prove this in the past.
It's hard to argue about this abstractly, so let's do this. If you give me the C++ code for a smart pointer that you claim is safe, I will construct you a code example showing use-after-free using that pointer.
> From what I've observed, you can't do this in Rust, if you try to write a doubly linked list you either have to use C-pointers that can dangle inside unsafe blocks, or eat the Rc overhead.
Yes, you can't do this in Rust. You also can't do it in C++.
C++ is good at making you think that you're using pointers that can't dangle, as evidenced by posts like yours. It's not good at actually preventing things like use-after-free.
> - template meta-programming feels like a different language, it's dynamic, functional, and the difference is refreshing. I like the mental switch you have to do to go from writing a C++ template to writing a C++ model.
I much prefer the static approach of Rust's generics to the untyped templates of C++--the fact that templates feel like a different language is a disadvantage in my view--but this is a huge tradeoff and it largely comes down to taste. This is unlike the memory safety guarantees of Rust pointers, which are not a matter of taste; safety is a formal property that C++ references simply do not satisfy and cannot satisfy no matter what.
https://github.com/martinmoene/observer-ptr/blob/master/incl...
I'm using a modified version in a personal library. It throws an exception on a nullptr dereference. I'm not sharing that version here because A. it's not ready, and B. You're definitely a better programmer than me and I don't feel like getting totally shit on today :)
I thought the whole point of the "world dumbest smart pointer" was that it's automatically nullptr'd for you so it can't dangle. I'm looking forward to hear why this isn't true. I've actually been brooding over this perceived advantage of C++ for a while now.
std::vector<std::string> strings;
strings.push_back("Hello");
std::observer_ptr<std::string> p(&strings[0]);
strings.clear();
std::cout << p; // use after freeTo use the header I linked it should be `nonstd::observer_ptr<std::string> p(&strings[0]);`
You also need to dereference p to use the stream operator.
I'm disappointed you presented such a contrived example. You also deliberately avoid const-correctness. That's a little insidious. You need to const everything manually in C++, so as a good C++ programmer you should const everything as you write C++. Only carefully omit const when you need mutability.
We all know C++98 is dangerously unsafe. Let's write your example in C++11.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <utility>
#include "observer_ptr.h"
// kill the noise
using std::cout;
using std::vector;
using std::string;
using nonstd::observer_ptr;
int main() {
vector<string const> const strings { "Hello" };
observer_ptr<string const> const p(&strings[0]);
strings.clear(); // not gonna happen
cout << *p;
}
» clang++ -std=c++11 immutable.cpp
immutable.cpp:11:5: error: member function 'clear' not viable: 'this' argument has type 'const std::vector<const std::string>' (aka 'const
vector<const basic_string<char, char_traits<char>, allocator<char> > >'), but function is not marked const
strings.clear(); // not gonna happen
^~~~~~~
/usr/local/Cellar/llvm/HEAD/bin/../include/c++/v1/vector:735: 10: note: 'clear' declared here
void clear() _NOEXCEPT
^
1 error generated.
EDIT: Down voted for legitimate rebuttal. Nice.So now using const is some kind of difficult task? Not much cognitive overhead there. I thought everyone was onboard with immutability these days.
My point is that safe low-overhead data structures with non-dangling, pointers protected from nullptr dereferencing ARE possible in C++ and not Rust. Yes, you have to put const after every type. Call that vigilance if you want. It's a really small price to pay IMO.
Edit: Down voted again. What's wrong with my point or code? I'm curious.
The fact that if you make everything totally immutable you can write safe C++ is (a) not true; (b) even if it were true, a totally irrelevant point in practice since not everything can be immutable. "C++ is memory-safe if you don't mutate anything anywhere" is a completely uninteresting point to the real world (even if it were true).
> My point is that safe low-overhead data structures with non-dangling, pointers protected from nullptr dereferencing ARE possible in C++ and not Rust. Yes, you have to put const after every type. Call that vigilance if you want. It's a really small price to pay IMO.
No, it's completely wrong. You have no protection from dangling references in C++.
I'd love to see an example without globals or an undefined behavior factory function.
Also, consider this:
std::observer_ptr<std::string const> const foo() {
std::vector<std::string const> const strings { "Hello" };
return std::observer_ptr(&strings[0]);
}
std::cout << foo(); // use after free, even with const!
This is how these discussions always go: someone presents an example of use-after-free in C++, someone else says "that's contrived"/"not real C++", and the discussion continues indefinitely. At some point we are going to just start debating "does anyone actually write use-after-frees in modern C++?", which is also a question we have empirical answers to by way of vulnerability databases and bug trackers, and the results don't look good for C++ there either.If your contention is that observer_ptr is completely safe, then we could have easily added it to Rust. We didn't for a reason: it's unsafe in Rust and unsafe in C++.
They are protected from undefined behavior, performant, and are excellent middle ground between reference counting or raw pointers.
I like Rust I just don't understand how I'm wrong about this single little pro C++ has over it.
Are you talking about how you can write data structure abstractions in C++ using unsafe feature (like std::observer_ptr) that are themselves safe to use? If so, that's exactly Rust's model! Rust's linked lists, for example, are written using unsafe code internally and present a safe interface.
> I like Rust I just don't understand how I'm wrong about this single little pro C++ has over it.
Because it's not a pro that you can write unsafe code in C++ without saying "unsafe"!
It's fine, I get you're very invested in this. I'm gonna go back to making stuff. I like the work you guys are doing and I don't want to give the impression I do not.
I understand I sound irritated here, but that's because we went through a lot of work to make Rust safe. It is irritating when people claim that languages that didn't even try to do any of that work somehow did it better than Rust did.
That being said, Rust is definitely a language I will continue to study. I have no doubt it's making me a better programmer.
EDIT: I find it funny that I'm always defending C++ here. C++ is like that kid at school who's not really your friend but you always get stuck doing project with. You end up spending a lot of time with him, so when the time comes that you hear someone talk bad about him you feel obligated to point out that he's a actually pretty alright dude.