
On Wed, Jan 31, 2018 at 4:52 PM, VinÃcius dos Santos Oliveira < vini.ipsmaker@gmail.com> wrote:
2018-01-31 20:25 GMT-03:00 Emil Dotchevski
: Where is the compile time error? Example?
Check the first Outcome tutorials.
This won't compile:
std::cout << (convert(text) / 2) << std::endl;
This will:
OUTCOME_TRY(foo, convert(text)); std::cout << (foo / 2) << std::endl;
Does this guarantee that your program is dealing with the error correctly? Not at all, if the context within which you call convert is not exception-safe, you'll get the same leak you'd get had you used exceptions. The difference is that you'd also get a compile error if you forget to check for errors, which a C++ programmer can't forget to do in this case. This is similar to how you have to deal with object initialization if you don't use exceptions. Compare: class foo { bool init_called_; public: foo(): init_called_(false) { } result<void> init() { .... init_called_=true; } result<int> foo() { assert(init_called_); return compute_int(); } result<void> bar( int x ) { assert(init_called_); //use x } }; .... foo a; OUTCOME_TRY(a.init()); OUTCOME_TRY(x,a.foo()); OUTCOME_TRY(a.bar(x)); Now the C++ version: class foo { foo() { //initialize, throw on errors } int foo() { return compute_int(); } void bar( int x ) { //use x } } .... foo a; a.bar(a.foo()); Note, I am not only making the point that the Outcome version is more prone to errors and more verbose, I am saying that even if you make no logic errors writing it, the result is a program that is _semantically_ identical to the one a C++ programmer would write using exceptions, complete with the bugs that could creep in if your code is not exception-safe. Literally, there is no upside to that style of programming.
You can't forget to handle the error case. You can look at a function and you'll immediately know if this function can fail or not.
In C++, we use noexcept to mark functions that can not fail.
You can't draw conclusions only by looking at anectodal evidence like
this. If you want to demonstrate that Rust-style error handling is more robust, you have to have a control, the same real-world large scale project written/designed for using C++ exception handling. Neither of us has a control.
At least you dropped the "axiomatic belief". But I haven't relied on anecdotal evidence. I specifically told you to show me /any/ code on Rust that is as complex as the examples I gave.
Yes, I understand that you like Rust and dislike C++. :) I am well aware of the difficulties in writing C++ code. Like I said, with some exceptions, there is usually a good reason for that.
C++ allows complexity to just snowball and it is not a opt-in feature. It's always there. Therefore, you always maintain useless state in your head when analysing C++ code. Go ask C programmers what they think about C++ exceptions.
You're making my point, that C++ exception handling is not an opt-in feature, it is inseparable part of the language, central to its object encapsulation model, etc. etc. I know what C programmers think about C++ and about exceptions in particular. Do note that they don't propose C libraries to be added to Boost or C++, they don't want to touch either. By the way, I have a lot of respect for C and for people who choose it over C++. I've also learned the value of using C-style interfaces between modules in a large scale C++ projects.
So you have to be able to make your point in the abstract, which is very
difficult. It is especially difficult because using either approach, a high quality development team can produce a robust program. But just because Google managed to build a phone using Java, it doesn't mean it was a good choice.
You still ignore the fact that I'm talking about a qualitative (not quantitative) property: more errors go to compile time errors. I have been focusing on such aspect since the beginning of the discussion.
I demonstrated why this is false, but there is no such thing as free lunch. Everything has cost. It is important to keep this in mind when criticising C and C++.
It's fact that you can't ignore the error because the code will fail to compile. Error cases are explicit.
Yes, using exception handling you can make mistakes that would be less
likely to make otherwise. Also, using C++ you can make a whole lot of mistakes you can't make in Java, that's one reason why some people use Java and not C++, but this doesn't make them good C++ programmers -- nor it means that there is something wrong with C++.
Agreed.
There are very many examples of things being very difficult to express in
C++ while being trivial in another language. There are usually good reasons for this, and there are many examples to the contrary. The ability to use RAII and exceptions to enforce postconditions is one such advantage.
Not sure what kind of postcondition you're talking about this time.
What postcondition, that depends on the design, but the effect is that you're making it impossible for control to reach contexts for which it would be a logic error to execute in case a previous operation failed.
If it is class invariants, you can have them without exceptions.
You can have them, but you can't know if they're been established because in case of a failure, control may still reach code that requires them to be in place.
And just one note about RAII: Rust does have RAII. No GC. A lot about the language was inspired by C++ knowledge.
Yes, I get that you love Rust. :)
I'll point out again that in C++ it is impossible to report an error from
a constructor except by throwing, and this is a good thing. I assume you disagree -- so what do you propose instead? It can't be OUTCOME_TRY, can it?
I'm not proposing you to code differently.
My question still stands though. If you don't use exceptions, in C++, how do you protect users from calling member functions on objects that have not been initialized? Emil