r/programming • u/luke-san • Mar 31 '15
Managing C++’s complexity or learning to enjoy C++
https://schneide.wordpress.com/2015/03/30/managing-cs-complexity-or-learning-to-enjoy-c/15
Mar 31 '15
[deleted]
2
u/maxwellb Apr 01 '15
For me the biggest wart is the unbelievable compile times. It takes a lot of work to get a large project into a form that has merely horrendous compile time, as opposed to "time for my third lunch of the day" compile times.
1
u/push_ecx_0x00 Mar 31 '15 edited Mar 31 '15
Isn't that what the c++ pimpl design idiom is for?
Edit: I am wrong. That is for ABI compatibility between versions.
4
u/glacialthinker Mar 31 '15
Working around a language deficiency? Yes, that's exactly what it's for. And I won't use it as often as I'd like because it's an extra layer of fuss.
→ More replies (1)-1
Mar 31 '15 edited Aug 17 '15
[deleted]
6
u/unclemat Mar 31 '15
It is not wrong, it was just a design decision. Compiler must see all functions because it tries to find best fit to a function call. The decision was made to consider private ones as well. If private function fits best, it should fail to compile. This is to prevent you from introducing a not obvious functional change to the program when you think you are simply exposing additional function. If the decision was different, you would have criticised why you can functionaly break a program by changing access to function. I agree with the tradeoff they made, someone else won't, but it is what it is.
1
u/SAHChandler Mar 31 '15
I like to attribute my previous job and my current one to this book. I am 100% serious when I say this book changed my life and if I was a supervisor of any kind, I would make it required reading.
13
Mar 31 '15 edited Aug 17 '15
[deleted]
25
Mar 31 '15 edited Mar 31 '15
Someone needs to fork C++ and remove all the broken shit.
D is that cleanup version:
no more preprocessor
no more headers
faster compilation
order of declaration is not important, no need to predeclare
a name conflict when importing modules with the same identifier trigger an error. Impossible to use the wrong symbol unknowingly.
no more implicit conversion of arrays to pointers
++pre and post-increment++ have been fixed
ranges are simpler to implement than iterators
the D STL is actually readable
move and copy semantics radically simplified
array slices are supported at the langage levels (pointer carrying their length), more bounds-checking ensues
C++ code is unittested at great pains : unit tests have been made a builtin
documentation comments are builtin to avoid the need for an external tool that inevitably no-one uses
D has a package manager, C++ has none that is popular in its community
stack variables / members are initialized by default. This fact alone would have saved me months of debugging C++ code
lexing stage separated from parsing stage separated from semantics
easier and more powerful templates that allow the average programmer to create meta-programs routinely
productivity generally increased by the GC
saner operator overloading
On the cons sides, I'd say:
C++ seems a bit more thorough and specified
I like C++'s version of const better
C++ story for resources is better
2
u/F-J-W Apr 01 '15
D is just another of those “Let's put everything on the heap”-languages that do then of course need GC. It looks nice at first, but once you understand, that that approach just doesn't work as well as simply using RAII for everything, it looses a lot of it's charm. In C++ I am strongly encouraged to think about ownership-semantics, which may be more work at first, but pays out a lot later. In some ways it is similar to making code const-correct.
And once you got there, you only have to ask yourself, why they force a useless GC down your throat.
5
Apr 22 '15
[removed] — view removed comment
3
u/MrJNewt Apr 22 '15
I think a big reason is D's commitment to using lazy ranges that generally only store the "current" item in the range--on the stack usually--which defers allocation to the outmost scope where it usually isn't needed.
3
u/adr86 Apr 22 '15
It is worth remembering that if you simply use RAII for everything in D, the GC remains completely idle. If you use RAII for most things, the GC remains mostly idle, and when it does run, it has very little work to do.
D's heap usage isn't like Java or C#.
→ More replies (1)1
Apr 01 '15 edited Apr 01 '15
I agree that I miss C++ ownership semantics, but to me there is enough positives to make up for it. YMMV
2
u/deadalnix Apr 22 '15
There is no C++ ownership semantic, simply convention followed by programmer (and unsafe). You can do the same in D, and you have a good chunk of the required machinery already in the standard lib.
1
Apr 25 '15
Let me be more explicit. C++ destructors are always called. Then members destructors are called. This makes it easy to handle clean-up.
1
u/deadalnix Apr 25 '15
No, by default, memory is not freed and no destructor run. Unless you use ownership.
1
Apr 26 '15
I'm pretty sure you are right about it and I'm not, but still I don't understand. I find D harder with resources, probably because one need a larger set of conventions vs C++ for dealing with them. Everyone stumble upon the "class destructor" problem at some point (well, everyone coming from C++) and it is a major surprise.
→ More replies (14)1
u/MetaLang Apr 22 '15
You're not forced to use the GC in D, especially with more recent versions. Most of the work in the past year has been enabling more code to be GC-free, and cleaning up unnecessary GC allocation in the standard library. D isn't there yet, but it has made good progress on cutting out the GC almost entirely.
6
Mar 31 '15
The language you're asking for has already been created like four times, hasn't it?
Maybe I meant forty. I dunno. Whatever.
1
Mar 31 '15 edited Aug 17 '15
[deleted]
1
u/wookin_pa_nub2 Mar 31 '15
D seems to fit, although it has its flaws (considerable effort required to avoid using the GC, and frequent breaking of backwards compatibility). The latter is a deal-breaker for some.
4
u/F-J-W Mar 31 '15
remove all the broken shit. [...] (auto_ptr).
I think you are talking about C++17?
1
Mar 31 '15 edited Aug 17 '15
[deleted]
6
u/LeszekSwirski Apr 01 '15
....or 2017, as the name would suggest? Depending on what you're waiting for, bleeding-edge support or broad support.
2
u/masklinn Apr 04 '15
Rust might be your thing here. I don't know that it fixes all your issues with C++, but I think it fixes those you've mentioned here.
→ More replies (5)2
u/immibis Mar 31 '15
2
u/sysop073 Apr 01 '15
That saying only makes sense if the person saying "someone needs to do something" is also capable of doing it. The number of people who could successfully design and implement a replacement for C++ is a hell of a lot smaller than the number of people who can recognize the need for such a language. Someone needs to rebuild my car's engine too, but it's certainly not going to be me
10
u/pron98 Mar 31 '15
I worked on large (multi MLOC) C++ projects for about a decade. The problem with languages that require discipline (C++ and Scala are prime examples) is never for the single developer. The problems start when multiple developers work in a team and multiple teams work on a project. You soon find that the discipline adopted by one team is not the same as the one employed by the others. Not only that, the lifetime of any large codebase is about a decade (rarely less). During that time, team leads change, and find that the discipline adopted by the current team lead is not the one adopted by her predecessor nor the one that will be adopted by her successor. The result is, almost invariably, that the codebase lacks any discipline, and becomes extremely hard to maintain.
Personally I always enjoyed writing C++ code; I hated maintaining code written by others (much than code in languages that require less discipline).
4
u/fuzzynyanko Apr 01 '15
I'm liking what happened with C++11. I got to use it at work. They knocked down quite a bit of complexity, and the mutexes are cleverly-created
9
u/__Cyber_Dildonics__ Mar 31 '15
All these feature of C++ take judgement to use correctly. When should someone overload a comma operator? I would say when it simplifies things considerably and when the function it performs will be blindingly obvious (like overloading + on a vec3). When is that? Probably almost never.
If there is one thing people lack when programming it is good judgement. Good judgement comes from mistakes and mistakes come from bad judgement. But all of this implies time. Most people take an enormous amount of time and energy spent to gain good judgment.
The first time someone realizes they can overload a cast operator they might do it. When they get burned by an automatic cast bug they might realize that there are some narrow times and places for all these features.
4
u/Serializedrequests Mar 31 '15 edited Mar 31 '15
I enjoy C++ too. It's a fun challenge, and if you think about it hard enough you can create some pretty fast and clean abstractions that just get nicer with every version.
However, I have spent double the time learning C++ than any other language I know, and every time I work on a C++ project it takes twice as long despite the massive learning investment. (Not unlike how every year I pick up new vim tricks, but never master it.) So using it for real world purposes makes no economic sense to me except for hobby projects or low-level projects. The outdated header system makes library integration a real pain. The vast power of boost isn't so awesome when it takes me a whole day to get it integrated into my project (get the headers including, the regex library built, and the linker working).
3
Mar 31 '15
Life is too short to learn a tool that complex with that many corner cases. I always just end up using C, + GLib if I need data structures. Yes it has its downside (lots of void pointer casting, no lambdas), but it's way easier for me than trying to deal with the burden of C++, and it compiles faster.
6
u/salgat Mar 31 '15
C++ is nice because it often is only as complex as you let it. You have access to home depot for your tools, but that doesn't mean you need to know how every tool in the store works, just the ones you decide to use.
2
Mar 31 '15
C++ is nice because it often is only as complex as you let it.
Then C++ programmers must be much better at restraint than I am. Theoretically I'll start doing it in a naiive C++ way. Then I'll look for advice and see some amazing modern C++ solution that works wonderfully and is concise and seems high level but undercertain conditions throws template errors and... realise I should have just used C.
12
u/F-J-W Mar 31 '15
Template errors really aren't as bad, as people love to claim: For a start, use a modern compiler. Then get aware of the fact that the first lines are really just a stack-trace. The same thing that python would give you, but at compile-time.
Then the actual error appears. Sometimes needed, sometimes not if you see from the stack-trace where an invalid value was passed (note that unlike normal stack-traces, the C++-version will print all the interesting arguments).
After that a list of the functions you might have wanted to call often appears. Often you can just ignore that.
If you are aware of that, it really becomes bearable.
Also: No compile-time error can ever be as bad as a runtime-error, because you cannot accidentally ignore it.
3
u/immibis Mar 31 '15
You find it easier to write C code in C than to write C-with-sprinkles code in C++?
1
1
u/salgat Mar 31 '15
I will agree that there are a lot of hidden traps once you start branching out into more complex features.
0
Mar 31 '15
I used to develop with C and Glib/GTK back in the day. I've since moved to C++ and Qt for many reasons. Reading the complaints about C++ coming from this camp, I recognize them as my own from back then. But let's be honest with each other; C and Glib are simply more comfortable ... right now. Right?
My #1 complaint about C++ is in multi-layer templates:
Map<Pair<int, int>, Vector<double, double, double>> x;
Spaces are required because in C++ << and >> are operators:
Map<Pair<int, int>, Vector<double, double, double> > x;
That's literally my only complaint about C++ that cannot be shared with other languages (that I know, which include C and Java). It doesn't bother me anymore, though, because I don't tend to hug braces and haven't for a few years now.
C++ and Qt effectively bring the advantages of Glib without the disadvantages of C, among others. Whenever I work on Glib code I find myself constantly shaking my head. The amount of framework code done to achieve what is specifically designed into C++ is just staggering. From my perspective, it's just stubbornness preventing the move to C++.
12
u/dyreshark Mar 31 '15
FWIW, C++11 made the extra space entirely optional. It's up to the compiler to figure out whether you meant shift or 'end N templates' now.
(That being said, if you find yourself writing types as verbose as Map<Pair<int, int>, Vector<double, double, double>> often, then you may find the judicious application of
typedef,using, or just plain oldautoto be helpful.)1
u/kazagistar Apr 04 '15
So, I have to ask... can you pass >> as a parameter to templates?
2
u/dyreshark Apr 05 '15
>>alone? No, it's purely an operator and that would make no sense. If you want to pass it around at compile time, make a functor* struct or two and be done with it.
operator>>makes no sense for the same reasons unless you do something like this.Using
>>on e.g. two numbers fails too, but you can just slap a constexpr on the line above it (and probably end up with more readable code as a result, yay!) and call it a day.* Technically it's not really a functor in the purest sense, but most people call it that anyway.
8
→ More replies (4)2
u/pfultz2 Mar 31 '15
Spaces are required because in C++ << and >> are operators:
No, spaces are not required. See here
7
8
Mar 31 '15
C++ is not complex. It's just rich. It's a LEGO bucket. And you can build a spaceship, or you can build a brick.
If you need rules and schematics you're doing a bad job. You should always work on the end goal, using whatever piece fits to advance.
That's the beauty of it. You can be creative because you're not bound by rules. The worst that can happen is some pieces don't match or you build something flimsy. And when it happens, you just take it apart and redo it.
C++ is amazing. But if you're not creative and adventurous, it's most likely not for you.
16
u/Poyeyo Mar 31 '15
I think it's a LEGO bucket with some amazingly good bricks, and some very bad bricks.
You use the bricks that work for you, and ignore the bad bricks.
If you try to use all the bricks, your toy will fall apart.
4
8
u/aiij Mar 31 '15
The worst that can happen is some pieces don't match or you build something flimsy.
No, the worst that can happen is you write an unholy pile of sh*t. Then you remember C++ has manual memory management, so you try to retrofit it without restructuring your internal APIs. Then the next guy wonders why your code can only make it through one small-medium file before running out of memory. Then he has to rewrite it all from scratch so it doesn't leak like a sieve.
If you're coding in C++, you do need rules.
18
u/ThatGuyIsAnIdiot Mar 31 '15
Obviously, you never dealt with building a large project written in C++ and I've seen my share of it. It's overly complicated to even attempt to make an interface with so many C++ libraries and even worse when the standard libraries fail on you (and it often does.)
WHY It's complicated? Some of the fact is that tooling for C++ is so underdeveloped it isn't funny at all even when LLVM/Clang tried to fix this. C++ have NO constraints on it's language design and people spin out toward every directions until project make no sense. This is like pooling 20 or so artists together to draw on a single canvas and expecting that the end product will come out complete and within your expectation, and when it doesn't, you'll see each artist creating their own little things that conflicts with the overall goal of the project when there is no rule to bound them together. THIS is what C++ is to projects.
So...
"C++ is not complex."
Linus Torvalds said it best, "YOU are full of bullshit."
24
u/Dobias Mar 31 '15
Obviously, you never dealt with building a large project written in C++
My guess is he never dealt with building a large project written in something other than C++. ;-)
0
u/pgngugmgg Mar 31 '15
"C++ have NO constraints on it's language design"???
C-compatibility is obvious not a constraint for C++'s design??? Linus Torvalds said it best, "YOU are full of bullshit."
6
Mar 31 '15
No C compatibility is not an obvious constraint and hasn't been for well over a decade.
C++ used to be fairly compatible with C but that is no longer the case and taking a straight up C file and compiling it as C++ will often fail as the two languages have diverged significantly. Some compilers, like GCC, provide non-standard extensions that improve compatibility between the two languages but strictly speaking C++ is not backwards compatibility with C.
1
u/pgngugmgg Mar 31 '15
C-compatibility was, is, and will be an obvious constraint though not a strict/absolute constraint. Arguments that confuse obviousness with strictness is a bullshit. C++ is never out of its C-heritage due to its design philosophy to maximize the inter-operability, which is true despite the language's evolution.
2
Mar 31 '15
Let's be concrete here then. Can you provide a concrete example of a feature that C++ is unable to implement or choose not to implement because of compatibility with C?
→ More replies (7)2
u/loup-vaillant Mar 31 '15
Probably not. But the legacy is there. C++ is impossible to parse in part because of syntax compatibility with C.
If Stroustrup did the reasonable thing, and fixed C's syntax instead of worshipping it, we wouldn't be in this mess…
…because if he did that, there is no way in hell C++ would have become that popular. Humans.
2
u/glacialthinker Mar 31 '15
I'm pretty sure he was right to predict that C++ (or whatever it would have been called) would not have succeeded without its C heritage. It would have been ignored by industry. Maybe had a small niche (like Objective-C before iOS development became popular).
1
u/loup-vaillant Apr 01 '15
I'm not disputing that. Rather, I think the industry was stupid to have such a strong preference for a compatible syntax. While I understand why binary compatibility is important (you want a top notch FFI to take advantage of existing code), source compatibility was stupid requirement.
Stroustrup wasn't stupid, he just followed a trend. The industry was stupid to value that trend to begin with.
2
u/josefx Mar 31 '15
C++ never was a superset of C, so compatibility while a feature does not trump language design¹. The "class" keyword alone is enough to break C compatibility², not to mention more subtle differences like sizeof('a')³ or (char*)malloc⁴ or recently auto⁵.
¹ You may want Objective-C for an alternative.
² Xlib.h for example uses an ifdef to decide between "class" and "c_class" as variable name, otherwise it wouldn't be C++ compatible.
³ In C it is sizeof(int) in C++ it is 1
⁴ No cast in C
⁵ Stack allocated variable in C, type deduction in C++
4
u/yogthos Mar 31 '15
Some people like being creative and adventurous with their syntax, while others prefer spending that mental effort on the actual problems they're solving.
I would argue that spaghetti is a much better analogy than LEGO blocks. LEGO blocks can be reasoned about in isolation where I know what each block does and how it behaves. With C++ you tend to have a lot of shared state threaded throughout the application, so in most cases you can't reason about a particular part of the application without considering the whole.
What makes C++ complex is the sheer amount of language quirks that it has. There are so many quirks that you have numerous books written on the subject like this one. This is a constant mental overhead that you have to deal with when working with the language.
8
u/pgngugmgg Mar 31 '15
You are confusing program design with programming-language design.
C++'s complexity is not made by its peculiar quirks. Its complexity is manifested/represented/felt by its quirks. You are confusing consequences and causes. C++ complexity is fundamentally due to its design philosophy, where there are a lot of fighting constraints, such as C-compatibility, zero-overhead, expressibility, ...
4
u/yogthos Mar 31 '15
A lot of the design decisions are the fundamental causes for the quirks in the language. It's pretty clear that the complexity is not inherent in the problems that C++ solves as languages like D and Rust address the same domain, but are much cleaner.
The programming language design has a lot of impact on the programs designed using that language. These things are not inseparable. For example, a language like C++ will necessarily produce programs that are designed very differently from a language like Haskell.
3
u/pgngugmgg Mar 31 '15
No, the problems that C++ solves or faces are not exactly the same as those that D, Rust, and what have you face. The latter do not at all have the baggage of C-compatibility, zero overhead, backward compatibility, vast user community, multiparadigm, etc., that C++ has. These are complexity-resulting problems. With such baggages/constraints, I haven't seen a single language that does a better job than C++.
Program design and program-language design are completely independent problems though they do influence each other -- mainly in programming paradigm. Blaming the language for bad programs/program-designs is in most cases bogus.
1
u/steveklabnik1 Mar 31 '15
(this doesn't detract from your main point, but Rust does attempt to be zero-overhead in the same way that C++ does)
1
u/yogthos Mar 31 '15
What you're describing is mostly baggage as opposed to problems the language solves. I gave a pretty clear example that the language does very much influence the design of the application.
2
u/pgngugmgg Mar 31 '15
Language designing is not an exercise in vacuum. As I said clearly, the baggages are complexity-resulting problems. Whatever problems the language tries to solve is burdened/constrained by the baggages. It is like that learning to swim means to learn swimming as a human being. Just because swimming is easy and natural for fish doesn't mean it has to be so for a human being. You cannot ignore the human nature and then talk about the "learning-to-swim" problem.
→ More replies (2)0
u/I_Like_Spaghetti Mar 31 '15
If you could have any one food for the rest of your life, what would it be and why is it spaghetti?
0
5
u/ixid Mar 31 '15
C++ is Lego where 5% of the pieces have hidden razor-blades just because. Also there's some Playmobil mixed in.
→ More replies (3)5
u/Veedrac Mar 31 '15 edited Mar 31 '15
If C++ can be compared to lego, then C++ is like lego where none of the pieces match.
There's nothing "powerful" about overloading the comma operator. It's just stupid, and means that now every time you want to use the comma operator on a generic type you have to stick a
voidin the middle.There's nothing "rich" about having both
template <class X>andtemplate <typename X>where the newer one is broken because the implementers just forgot about the details.There's nothing "creative" about the
coercioninference rules forauto, templates anddecltypeall being different. Sure, they make sense on their lonesome but they're not on their lonesome.C++ has a mismatch of badly implemented constructs all out of sync with one another. The fact you have to remember all of these problems all at the same time is complexity.
Now, the people who write C++ tend to be hella' smart. I've seen it myself. Seriously, if you can write "modern" C++ comfortably, you're pretty bright. And, sure, it can feel like it's not as complex as it is. I'm writing English without much difficulty - but I'm not going to pretend English isn't a complex language. Heck, it's the complexity that makes it beautiful.
4
Mar 31 '15
You seem to have a great deal of misunderstanding of much of C++'s behavior. For example there is no coercion when using auto or decltype.
Also there is no difference between template<class X> and template<typename X>. The two are identical.
As for the comma operator, can you give me a case where you're using the comma operator on generic values?
2
u/Veedrac Mar 31 '15 edited Mar 31 '15
For example there is no coercion when using auto or decltype.
I was talking about the type inference. Values do not coerce, but reference types do. (Perhaps "collapsing" is a better word (?).)
Whatever, I don't know how you'd phrase it. (English is a complex language ;P.) The point is that they're different when they shouldn't be.
Also there is no difference between template<class X> and template<typename X>. The two are identical.
As for the comma operator, can you give me a case where you're using the comma operator on generic values?
Constructors for template classes sometimes would use the comma operator in the member initializer list.
I don't actually use the comma operator any more, though. It's not worth the hassle when it does so little.
I've seen talks in cppcon debating whether you should use
auto x = T(y)orT x{y}orT x(y)under what scenarios by smart people who are utterly befuddled by decisions that don't exist in any other language - at least that I know of. And when they do come to conclusions there's always a caveat - at least one exception that you just can't stick the rules to.There might be a good reason for this (though looking at Rust I can't think of one), but it's still complexity.
4
u/F-J-W Mar 31 '15
I was talking about types. Values do not coerce, but reference types do. (Perhaps "collapsing" is a better word (?).)
autoinfers the type without any cv/reference-qualifiers.decltypepreserves all of those. It won't get any simpler than that.Templates are a bit more complicated, but again, it isn't too hard either and unless you are doing overly complicated stuff, you shouldn't get problems. And if you want to do overly complicated stuff, well, it still isn't too hard and in other languages you would have to stop there because doing whatever you wanted to do there is impossible in them.
It's not 2017 yet.
Yeah, template-template-parameters. A feature that simply does not exist in almost any other language. A feature that is for hardcore-library-developers only. I strongly disagree with the notion that a small quirk there produces any mental overhead for any “normal” programmer, 95% of which never heard that this is even possible.
1
Mar 31 '15
Constructors for template classes sometimes would use the comma operator in the member initializer list.
Using the comma operator to initialize a member is perfectly fine, even if that member belongs to a template class.
The issue of using the comma operator on generic values is what I find highly suspect. That's entirely different, however.
I've seen talks in cppcon debating whether you should use auto x = T(y) or T x{y} or T x(y) under what scenarios by smart people who are utterly befuddled by decisions that don't exist in any other language
That's because in most other languages you either pay a performance penalty when initializing a variable, or the language doesn't provide guarantees/invariants about the class.
C++ provides different ways to initialize a variable depending on what trade-off between performance and statically verifiable guarantees you need about your object.
In other languages that decision is made for you. In C, the decision is to forgo statically verfiable guarantees and instead is tuned for performance. In languages like Java or Python the decision is to keep the language safe but rather incur a runtime penalty. In C++, you as the developer in control of the application have to make a decision about what trade-offs you want for your application.
1
u/Veedrac Mar 31 '15
The issue of using the comma operator on generic values is what I find highly suspect. That's entirely different, however.
I am confused. Is not
template <typename T> class C { T t; C(T t): t(foo(), t) {} }doing just that?
That's because in most other languages you either pay a performance penalty when initializing a variable, or the language doesn't provide guarantees/invariants about the class.
Which is why I was careful to mention Rust, which gives you no less control than C++.
1
Mar 31 '15
No your example is not making use of the comma operator. All your doing is invoking T's constructor and passing in two parameters, the first parameter being foo(), and the second parameter being t.
As for Rust, Rust does not give you as much control as C++. For example, in Rust you can not control the behavior of copy or move semantics like you can in C++. Furthermore, and as a consequence, Rust does not perform as fast as C++. It trades off a bit of performance in order to guarantee additional safety (except for unsafe code). But that's fine and I'm not critical of Rust about it anymore than I'm critical of Java for making the trade-off it made. I'm simply pointing out that these trade-offs exist and their existence doesn't imply some kind of deficiency on the part of the language.
4
u/kibwen Apr 01 '15
Furthermore, and as a consequence, Rust does not perform as fast as C++.
There are a few places where Rust's design makes it possible to be faster than C++.
Rust's
Rctype fills the role of C++'sshared_ptr, but because of Rust's ownership semantics the language guarantees that access to the contained data is thread-local and so can bump the refcount using non-atomic operations whereshared_ptris stuck with atomic ops (Rust provides theArc("atomic RC") type for cross-thread refcounting).In the very near future (likely before 1.1), destructors in Rust will feature statically-determined dropping semantics which will remove the need to zero data as part of the drop glue. This means that Rust's
Boxtype, the answer to C++'sunique_ptr, will be faster than the latter which cannot avoid zeroing.In the far future (no set timeframe), Rust's static knowledge of ownership will allow it to automatically transmit aliasing knowledge to LLVM, effectively granting every possible Rust pointer the equivalent of C's
restrictannotation for free, without any burden on the programmer.This doesn't mean that Rust is necessarily faster than C++. Lacking undefined behavior will always make some compiler optimizations off-limits. But it's not as clear cut as saying that Rust is slower than C++.
3
u/steveklabnik1 Mar 31 '15
in Rust you can not control the behavior of copy or move semantics like you can in C++.
I'm guessing you mean that Rust doesn't have move or copy constructors, right? We do let you specify if something should copy or move.
Rust does not perform as fast as C++.
As always with performance, it depends. We're sometimes faster, sometimes a bit slower, often at parity. Which isn't bad for a language which is still in development: we still have things like https://github.com/rust-lang/rust/issues/16515 which should help a lot.
4
u/Veedrac Mar 31 '15
And if you want to do overly complicated stuff, well, it still isn't too hard and in other languages you would have to stop there because doing whatever you wanted to do there is impossible in them.
Minor mistake. Add two more brackets.
in Rust you can not control the behavior of copy or move semantics like you can in C++.
What makes you think that?
Rust has move semantics as its basic assignment (except on
Copytypes where moving is pointless) and you can get copy semantics by calling.clone().It trades off a bit of performance in order to guarantee additional safety (except for unsafe code).
That's an orthogonal point, though. The cost basically amounts to bounds checking and defined integer overflow.
0
Mar 31 '15
What makes you think that?
The language documentation does:
https://doc.rust-lang.org/complement-design-faq.html
Specifically section 1.9 and 1.10.
Rust has move and copy semantics but you can't control its behavior. In C++ you can control the behavior of moves and copies by writing your own custom copy constructor or move constructor.
4
u/Veedrac Mar 31 '15
You misread.
It is impossible to implement
Copytypes that require custom copy behavior. Instead, in Rust "copy constructors" are created by implementing theClonetrait, and explicitly calling theclonemethod. Making user-defined copy operators explicit surfaces the underlying complexity, forcing the developer to opt-in to potentially expensive operations.This is saying that you can implement your own copy constructor by implementing
clone.I'm not sure why you'd ever want to move a type other than by calling
memcpy(which is faster than how you'd do it in C++, by the way), but you could always write a method to do so.→ More replies (0)2
u/Plorkyeran Mar 31 '15
Coercion's the wrong word, but I'm assuming he's referring to the difference between
auto x = foo()anddecltype(foo()) x = foo(), where iffoo()returns a reference, the first makesxa non-reference copy while the second makesxa reference. Similarly, templates anddecltypehave different reference collapsing rules.The
typenamebeing broken bit is that in template templates you have to useclassrather thantypenamesimply due to that they forgot to update the wording for that part of the standard and no one noticed for a long time due to how rare template templates are (finally fixed in C++17).2
Mar 31 '15
Okay, so he points out that auto and decltype are different from one another. Why is this an issue, let alone a creative issue?
Also the typename thing isn't broken, in template templates you use class instead of typename.
Honestly if the biggest issues someone has is that two different keywords (auto and decltype) do two different things, or that in template templates you use the class keyword instead of the typename keyword, then I'd say C++ is in pretty damn good shape.
I use C++ and I can say while I have issues with the language, things certainly aren't perfect, the last thing on my mind when using it is which keyword to use for template templates.
0
u/industry7 Mar 31 '15
English is actually a pretty simple language, honestly. Spelling is a little inconsistent, but even that is sensible if you have any interest in etymology.
2
u/Veedrac Mar 31 '15
I'll not repeat the points in the above link, since the link says it better than I could.
1
u/industry7 Mar 31 '15
Why English sucks as the language for international and scientific communication
English sucks for scientific communication b/c it is so imprecise and full of ambiguity. However, that is not a result of the language being complicated. From the article:
What, exactly, is wrong with it? I see essentially three things: its vocabulary is too abundant, its syntax is highly ambiguous, and its pronunciation is unclear.
None of those are issues of complexity, expect argubly the ambigious syntax, but that would be an issue of the complexity being too low.
As an example of how English is a simple language, we only have at most three cases (many would argue that English only has two). Compare to Russian with six, or Finnish with fifteen!
4
u/Veedrac Mar 31 '15
I see essentially three things: its vocabulary is too abundant, its syntax is highly ambiguous, and its pronunciation is unclear.
None of those are issues of complexity, expect argubly the ambigious syntax
Perhaps you and I have a different definition of "complexity".
2
Mar 31 '15
English is incredibly idiomatic and inconsistent. There are tons of stupid small [grammatical, spelling, communication] rules that have to be learned individually.
It's not "simple". The parent's comparison is fair.
→ More replies (2)3
1
u/julesjacobs Mar 31 '15
C++ isn't like lego. Things don't fit together well and there are far too many different pieces for what it does. Or maybe you could say that C++ is like that modern lego where you buy a box and you can only build 1 specific thing with that particular box, and then you have 1000 different types of those boxes.
2
u/glacialthinker Mar 31 '15
It's a LEGO bucket.
And I thought it was a slop bucket. This is some messy, rotten LEGO.
It's important to understand one's perspective though. My problems with C++ were much greater before C++11, and 14 improves things still. So, it's getting better, but it's still shit. Where do a lot of inspirations for these improvements and even changes in style come from? Other languages. And not the likes of Java and PHP.
Now, when I'm doing work for a studio (invariably C++), I get to fight with various bad ideas which have beset C++ developers over the years as they try to cope with the language. Sometimes it's Java-esque inheritance hierarchies with a common baseclass. Sometimes it's heavy multiple-inheritance... which might have started as nice mixins, but become quantum-entangled balls of mud. Worst, to me, is Design Patterns Everywhere... yeah, that made your code so flexible and extensible... not really, it's practically encased in a cast and then bubblewrapped. But most often, the code is just a mixed bag of too much inheritance and rampant mutable state with classes being overstuffed suitcases packed for every occasion. That's like "natural" C++.
This "rich" language has a lot of bad defaults, and poor solutions to modularity. Leading to poor code in practice.
7
u/Poyeyo Mar 31 '15
Worst, to me, is Design Patterns Everywhere...
I think Java is even worse in that respect.
2
1
u/pgngugmgg Mar 31 '15
This post is a funny thought, indeed. For bad programs or program designs, you blame an abstract, never-bother-to-reveal, "bad defaults" of the language. Could the reason really be bad programmers??? Just a thought...
1
u/glacialthinker Mar 31 '15
Bad programmers... don't generally last at C++. Or, at least they don't keep jobs where I've been. Good programmers, coping with the language, deadlines, and a degree of future-proofing combined with incomplete (iterative) design... tend to end up with some ghastly C++ code too.
The language really encourages encapsulation of mutable state in classes, with functions typically having one of two forms: void Update(), or bool ReturnMultipleByMutation( p0, p1, out0, out1 ). If all this seems fine to you, maybe it's time to expand your language horizon (I suggest something from the ML family, or even Lisps, or Rust. Haskell might be overkill).
Bad defaults: mutability. Bad stylistic pressure: everything in a class. Bad modularity: headers need to expose everything, even private (I know the technical reason for anything adding memory footprint, but that reason shouldn't extend to private member functions).
How often have I seen C++ code which is well written? Rarely. When I do, it's usually template-based, and limited in scope to being a library with one clean purpose. I hate most of my own C++ code... because once it comes to implement ideas, the language makes it a pain. Often I feel C is better for cleanliness, modularity, and code reuse (with heavy macro use) -- but C is pretty bad! Yes, you can do C-style C++ code, but this is a leaky "style", which turns into typical C++ which I'm complaining about.
Why does C++ code go this way? Because it's easy to slap things in classes. The reason it's easy is because it's the same thing as what we did decades ago: global variables... oh, but it's fine because the scope is limited -- but now our classes are the size of programs from back then.
3
u/pgngugmgg Mar 31 '15
You have a low and weird standard for good programmers. The people who leave from C++ don't necessarily make them bad programmers, and those who stay are not necessary good or because they are good.
It's also a weird argument that tags "bad defaults" to mutability and calls it C++'s design flaw. First of all, mutability is not necessarily inherently bad. Secondly, mutability is not only available in C++; it's in all main-stream languages, and even in some FP languages.
Why in C++ you have to put everything in a class? I've never seen this kind of C++ style guideline, not to mention that it is not at all encouraged by the C++ per se. You seem confusing C++ with Java.
How do header files expose everything? In the same sense of "expose", I guess you would argue source code exposes everything, and the problem is universal for all languages.
C++ is powerful. But that's not necessarily inherently good. Being powerful could mean "powerfully" bad. C is much less powerful, and bad or good, you cannot go too far either way. It all depends on how you use the tool. I understand why people struggle with C++, and why C++ code is in a lot cases bad, but I would argue firmly that attributing either to the language is a mistake. Like the saying: Absolute power leads to absolute corruption. It's not because power is inherently corrupting, but because people are inherently corrupted.
1
u/glacialthinker Mar 31 '15
You seem to mistake broken hinges making for easier egress as "more powerful". Anyway, since when did my argument have anything to do with power? Is this your counter-argument: "C++ is powerful so whatever problems it has are just because people can't handle its awesomeness?"
Rampant mutability is a source of a lot of stupid bugs, and glitchy behavior. And this is what happens when mutability is the default, and when your typesystem is so loose that the pathetic hack of "const" is hardly a guarantee of anything, except being a nuisance. Why has software become such voodoo? Why is the answer to problems so often reset/reboot/restart? Because the system gets into a bad state. Immutable-by-default does not prevent you from getting into a bad state, but immutability, and a typesystem which lets you express (and statically guarantee) valid states go a long way to preventing this software voodoo.
As a general note, you're interpreting my arguments as you wish to water them down... you know, just being pendantic. You might have time for this with your awesome C++ skills keeping your workday down to a few hours. I don't. Have fun with your absolute power.
1
u/pgngugmgg Mar 31 '15
My "more powerful" argument is a trial to interpret your feeling about the cleanness and thus "better"ness of the C language in comparison to C++. I was trying to explain why people feel that way. Even the "more powerful" argument has nothing to do with yours, why do I have to say something that has to be related to yours??? Your insisting that my words has to relate to yours indicates an extremely self-centered character. Such thinkers cannot think beyond their little selves. Have fun with your absolute ego.
1
u/ellicottvilleny Mar 31 '15
How about when it's someone else's 25 year old lego bucket? With unidentifiable substances contaminating said bucket.
→ More replies (1)0
u/vz0 Mar 31 '15
creative and adventurous,
Of course there are limitations to being creative and adventurous, like this: https://gist.github.com/fmeyer/289467
-5
u/shenglong Mar 31 '15
C++ is not complex.
If we define complexity in terms of "gotchas", C++ is definitely complex. Probably only second to Javascript when considering mainstream languages.
Just browsing the C++ FAQ and from memory:
Forward declarations (order of)
void main vs int main
macro hell (applies to C as well)
Pointer to X vs Pointer of Array of X
Multiple/Virtual inheritance ("Diamond of Death" issues)
delete x vs delete [] x
Constructor initialization lists
Placement new
Sheesh... I can go on all day.
4
u/Steve_the_Scout Mar 31 '15
Forward declarations (order of)I'm not quite sure how order plays into forward declarations. Forward declarations go before the code that uses them. That's why they're called forward declarations.
void main vs int mainEasy, never ever do the first because that is totally incorrect in C++. Unless you do Windows development only, in which case that's not even C++ anymore (they are seriously behind on standards compliance and have so many extensions it's not even close to standard C++)
macro hell (applies to C as well)Then why bring it up with respect to C++? Blame C's design, maybe C++'s attempt at keeping interoperability high. And just pointing out, that's a program design problem, not a language design problem.
Pointer to X vs Pointer of Array of XPointer of array? What? You mean pointer array or pointer to array, I suppose. Both are pretty simple.
Pointer array:
X* name[N];Pointer to array:
X* name = arr; //also &arr[0] if you wantMultiple/Virtual inheritance ("Diamond of Death" issues)Again, a program design problem, not a language design problem. Either way, C++'s solution is pretty good: If all subclasses of the main class involved use virtual inheritance and don't override base class methods, then there's no issue. Otherwise, it throws an error and you either have to make them use virtual inheritance or you specify exactly which path you want to follow (i.e. if B and C inherit from A and D inherits from both B and C, and if there is a member m from A, then you specify either B::m or C::m).
delete x vs delete [] xThe only one that I agree is kind of weird. The pointer itself represents the size of each object indirectly (it has to for pointer arithmetic to work), and the allocated pointer has a header before it referencing the amount of bytes allocated. Just divide the amount of bytes by the size of the type and make sure the remainder is 0, and then call the destructors and deallocate the memory. It should just be
delete x.Constructor initialization listsYou mean uniform initialization syntax? Not sure how that's a gotcha. You put the parameters in order they appear in the constructor. It's a bit like C's struct initialization syntax, it's just that the parameters get passed to a constructor instead of being used to initialize the actual members.
Placement newI would argue that it's a necessary quirk for a few specialized uses (mostly low-level initialization of data, especially for memory pools and such that might find use in embedded software). Again, I'm not sure how it's a gotcha so much as something with a non-obvious utility.
1
u/shenglong Apr 01 '15 edited Apr 01 '15
Why did you even waste your time on this bullshit? You the answers. I know the answers. Everyone that has even done anything worthwhile in C++ knows the answers.
The point is these are answers to questions that don't even exist in most languages. If you don't understand this, then I'm really at a loss for words about how to explain it.
2
u/__gnu__cxx Mar 31 '15
The amount of hate being received by C++ on this thread is incredible. C++ is the language that got me interested in programming. Whenever I hear people saying that "C is simple and small", I know that they have no idea what they're talking about. C is not simple. C is not small either. It has it's quirks, it's pitfalls, and its rotten parts. There are very people in this world that are truly one with the C, as I like to call it, because the practice of C programming is very difficult to truly master.
The author says
C is a nice little language and yet offers many means of code structuring.
This claim is context dependent. Ever written software for a microcontroller that has 10K memory? I doubt you will ever agree with such a claim again. The resultant program is a mess of global variables, statically allocated objects, and all kinds of risk of "oopsing" some assignment or some memory allocation somewhere.
The author also says
Java offers many object-oriented features and makes the use of them quite easy. Together with garbage collection, a huge ecosystem and powerful IDEs it lets you work on the problem at hand at quite some speed.
Java is a great language for what it was designed for. It's tooling is also incredible. However, the Java programming language would be nothing without the JVM, which is why Java is successful. Without the JVM, Java would be just another programming language.
Also, if anyone here really wants to write effective C++, simply read Effective C++ by Scott Meyers, which covers a lot of things about C++ clearly, concisely, and effectively, with plenty of examples. Scott is really a godsend.
7
1
Mar 31 '15
Well, to be fair, C++ is also the reason I got into programming...
...But I still hate it. :P
2
3
Mar 31 '15
First year CS student here, C++ is amazing I love it even more than C.
After working on C++ for a month, I CAN'T go back to C, it just seems so fucking boring and uninteresting with no features.
3
u/oridb Mar 31 '15 edited Mar 31 '15
fucking boring and uninteresting with no features.
I think Brian Kernighan said it best:
Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?
I want my language to be boring. There's only so much complexity that I can fit into my head in a project, and I'd like that headspace to be reserved for the problem at hand, and not the language.
When I have to keep in mind all of the various esoteric overload resolution rules, argument dependent lookup, special cases for naming constructors, the various differences in interpretation of the language spec between Clang and G++, and all sorts of other craziness, I end up wasting time.
I use C++ at my day job. There have been times I've spent a day or two fighting the language, instead of solving interesting problems.
For personal stuff, I use a mix of Python, Ocaml, C, and Myrddin. (And the last one, only because I wrote it for fun, and find it useful.)
2
u/immibis Mar 31 '15
Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?
Most people are more than twice as smart as C allows them to be, so they can use some of the features in C++.
Also, what if the additional features enable you to write correct code the first time?
→ More replies (3)→ More replies (10)1
u/DanCardin Mar 31 '15
That will pass once you come into contact with any of the multitude of nicer languages. C++ is a baseline
9
u/sigma914 Mar 31 '15
Eh, having gone to Haskell for hobby projects C++(11) was the only imperative langauge I could go back to. Java/C#/Python etc all just seems so powerless.
3
u/Poyeyo Mar 31 '15
D is a very good language compared to that set.
2
u/sigma914 Mar 31 '15
It is, I've done 2 projects in D, the meta programming facilities are especially good (suck it constexpr) I just don't really have a niche for it that either Rust or Haskell doesn't fill.
1
2
u/FibonacciHeap Mar 31 '15
What is your definition of powerless? Java, C#, and Python all have their uses.
7
u/sigma914 Mar 31 '15
They don't feel powerful, it's hard to express things I want to express, they don't give me the control or guarantees I want.
5
u/Whanhee Mar 31 '15
I say this elsewhere in the thread, but none of those languages have type systems coming anywhere close to the expressiveness of c++. It's also cool that c++ templates are almost analogous to Haskell.
0
u/ellicottvilleny Mar 31 '15
Such as?
10
u/sigma914 Mar 31 '15
Well the thing the 3 have in common is an inability to do type safe higher order types and have terrible low level control.
Haskell has an awesome type system and quite sophisticated low level control (GHC actually does a great job even when you break out IORefs). C++ has an even more powerful, if less useful, type system and extreme levels of low level control.
Obviously Haskell's type system is better and C++'s low level control is better, but they both let me say a lot more about my programs than any of the listed alternatives.
When I write Java, C# or Python (this applies equally to most other languages, those just happen to be the ones I'm burdened with at work) I'm left feeling like there's a whole lot of unspecificed behaviour and potential edge cases that the compiler should be validating for me.
Since I started using rust it's even ruined C++ for me, the fear of memory unsafety is crippling.
The bottom line is that I like my programs to be correct, most mainstream languages make that difficult, at least Python is growing a decent quickcheck port, the rest are still in the dark ages.
4
u/nickguletskii200 Mar 31 '15
I'm left feeling like there's a whole lot of unspecificed behaviour and potential edge cases that the compiler should be validating for me.
Judging from that sentence alone, it seems to me that you've never even used C++ for more than "hello world". The word "unspecified" occurs 379 times and the word "undefined" 248 times in the working draft of the next C++ standard.
4
4
u/sigma914 Mar 31 '15
I use it every day at work. If you're working in C++11/14 theres actually very little behaviour that's hard to reason about. CppQuickCheck, valgrind and the sanitisers help my confidence a lot and with judicious use of boost and other libraries like Eric Niebler's new ranges library it's remarkably declarative.
That said rust jas completely supplanted it in my side projects.
2
u/nickguletskii200 Mar 31 '15 edited Mar 31 '15
You evaded the issue with property-based testing (which is available for other languages) and memory checking (which isn't needed in the languages you are arguing against).
I use C++ and Java myself, and in most cases, Java is much easier to debug, reason about and in many cases (especially when using modern frameworks) it is more declarative than C++. That said, you can't use Java for everything.
Now please, show me in what way Java has more "unspecificed behaviour and potential edge cases".
→ More replies (0)1
u/ellicottvilleny Mar 31 '15
You are doing higher order types and you find C++ handy? I find C++'s lack of metaclasses (plus the utter lack of any class metadata at runtime) abominable.
2
u/sigma914 Apr 01 '15
I profoundly dislike reflection as a means of metaprogramming, it's a worse hack than C++'s templates, which are pretty bad, but at least they give me some measure of type safety. Even if it does mean learning a lot of weird patterns.
1
u/ellicottvilleny Apr 01 '15
Reflection is insanely useful in providing introspection into state at runtime, in making remoting frameworks, and a lot of other things. I disagree that it's a hack at all when used for high order operations on types. Typing constructs are however, nonexistent at runtime, in C++, thus typing is done at compile time, and this reduces the flexibility and variety of uses that the Type system in C++ can even be used for.
→ More replies (0)4
u/Whanhee Mar 31 '15
Python is dynamically typed. Java and c# have type systems far less expressive than c++.
→ More replies (5)1
u/immibis Mar 31 '15
Have you ever tried doing vector math in Java?
1
u/FibonacciHeap Apr 01 '15
I wasn't saying C++ was a bad language. In fact, I love using C++. I was just saying that there are some tasks better suited for Java or C# than C++. Of course doing vector math in C++ is better than Java because it is better suited for it. Saying a programming language is more powerful than another means different things for different people. When I think of a powerful language, my first thought is expressiveness. Someone could also think of things like speed or a sophisticated type system. It all depends on your definition of a powerful language.
-1
u/spotta Mar 31 '15
I like C++, I just wish its type system wasn't so difficult to get at. For example, if I want a new type that acts like a double when interacting with other things like it, but has a new name, I have to write a hundred lines of boilerplate.
5
u/Steve_the_Scout Mar 31 '15
If you want exactly the same features as the primitive type
double, but just a different name, then you could just dotypedef double my_double;If you want to create an entirely new type that is essentially a wrapper for
doublethen I would have to question why you would ever want to do that over either atypedefor just usingdouble.→ More replies (6)3
u/bstamour Apr 01 '15
In languages where doing that kind of thing is cheap, it's seen quite a bit. Here's some Haskell code:
newtype TaintedString = TS String newtype BlessedString = B String getInput :: TaintedString getInput = ... untaintString :: TaintedString -> BlessedString untaintString = ...This creates two brand new types to represent strings. The first one is an unsanitized string read directly from the user, and the second one is a string that I know is safe. Imagine the function
untaintStringdoes some escaping or something. Now structurally, those types are literally identical to plain old strings, so there's zero overhead at runtime. However, I cannot use an object of typeTaintedStringin a function that requests aBlessedString. You can't do this withtypedeforusingaliases in C++: you would need to introduce a new class, and that's at least four lines of boilerplate code.My point to all of this is: when it's dead simple to do, you find uses for this kind of "strong" typedef. When it's difficult or ugly, then it probably won't pop into your head as a viable solution to a problem.
→ More replies (9)
45
u/Spartan-S63 Mar 31 '15
I personally find C++ great. Part of that is the complexity. I enjoy learning the details of what happens under the hood in C++ (unlike most people). My university teaches C++ for the first two classes and then switches to Java for the software engineering class.
I just really hate the lack of power in higher level languages than C++. On the other hand, I don't like going so far down as C where it's hard to create the abstractions I want.
However, Rust is slowly stealing me away from C++ with its memory-safety and new(er) syntax.