3 ms·
Every time you say this, someone rebuts you, or asks you to explain, but you seem to completely ignore any feedback. Could you be more specific? Rust has nowhe
by dbaupp 8y ago
Every time you say this, someone rebuts you, or asks you to explain, but you seem to completely ignore any feedback. Could you be more specific?
Rust has nowhere near the incidental complexity of C++: there's so many features/syntaxes in C++ that have surprising interactions. For various reasons (such as not aiming for direct C compatibility), Rust has been able to avoid those for the most part.
Even just initialization syntax in C++ is complicated. For instance, what does this print?
#include <iostream>
#include <string>
#include <vector>
class Foo {
public:
Foo(int a) {
std::cout << "Foo " << a << std::endl;
}
};
int main()
{
Foo paren(0);
Foo brace{0};
std::vector<int> int_paren_0(0);
std::vector<int> int_brace_0{0};
std::vector<int> int_paren_2(2);
std::vector<int> int_brace_2{2};
std::cout << "int_paren_0 " << int_paren_0.size() << std::endl;
std::cout << "int_brace_0 " << int_brace_0.size() << std::endl;
std::cout << "int_paren_2 " << int_paren_2.size() << std::endl;
std::cout << "int_brace_2 " << int_brace_2.size() << std::endl;
std::vector<std::string> string_paren_0(0);
std::vector<std::string> string_brace_0{0};
std::vector<std::string> string_paren_2(2);
std::vector<std::string> string_brace_2{2};
std::cout << "string_paren_0 " << string_paren_0.size() << std::endl;
std::cout << "string_brace_0 " << string_brace_0.size() << std::endl;
std::cout << "string_paren_2 " << string_paren_2.size() << std::endl;
std::cout << "string_brace_2 " << string_brace_2.size() << std::endl;
}
Trick question! It segfaults, because string_brace_0 (and only that one, not even string_brace_2) is trying to be a vector of size 1 with an element constructed using the std::string(const char *) constructor (i.e. the 0 literal is becoming a null pointer to pass to that constructor), and this calls strlen on a null pointer. If the string_brace_0 stuff is removed, it prints
Foo 0
Foo 0
int_paren_0 0
int_brace_0 1
int_paren_2 2
int_brace_2 1
string_paren_0 0
string_paren_2 2
string_brace_2 2
That is, constructing Foo is the same with () or {}, constructing vector<int> with () is different to {} (the latter uses the explicit initializer_list constructor), and constructing a vector<string> with () is different to {} sometimes, and the same other times!
Unfortunately, random interactions like this aren't an isolated occurrence in C++ (especially due to C compatibility stuff, but it can't be avoided even using only "modern C++" constructs, as above): I suspect if you name any feature of Rust, someone will be able to demonstrate that the equivalent part of C++ is significantly more complicated to use[1]. That is, C++ is probably more complex than Rust on a per-feature level, not just some nebulous whole-language complexity.
[1]: The borrow checker is possibly the only thing that this doesn't work for, but I think there's a fair argument that it is actually simpler in Rust: a C++ programmer ends up having to do something similar, in their head, with no computer assistance.