40 ms·
C++ and the Culture of Complexity (2013)
- airstrike 9y agoIt takes balls to imply that one may use Java in lieu of C++ so as to reduce complexity.
- thebear 9y agoAuthor here. Quote from the first paragraph of my blog post: "The decision to implement the math backend of GreaterThanZero in Java was driven by other considerations, primarily the appeal of Google App Engine as a hosting platform."
- ajeet_dhaliwal 9y agoIn my experience this disease afflicts more than just some C++ programmers, the immaturity is boundless. I’ve noticed some colleagues even think there must be something wrong if code looks simple.
- ioquatix 9y agoYes, C++ is a complex language. Yes, it has a ton of warts if you know where to look. But, you can write beautiful software with it, and it can even look beautiful too. Yes, there are alternatives, but when it comes to performance, expressiveness and actual deployability, C++ is pretty awesome.
- lallysingh 9y agoMeh. The performance is almost never worth the huge complexity jump. Instead, profile an app in a higher level language and if any part's too slow, implement that in C/C++. That'll quite often be a low, single digit percentage of the app. Get the performance for substantially less engineering/maintenance cost.
- foo101 9y agoC++ is a complex language no doubt. But software written in C++ need not be complex. Java, on the other hand, is a simple language. But the kind of unnecessary complexity I have seen in Java-land (EJBs, Spring, etc.) has no parallel in the C++-land. So going by your argument, I would choose C++ over Java to avoid the complexity jump, then profile the app, and if any part's too slow, improve that again in C++.
- narayanbs 9y agoEither you are confusing verbosity with complexity or you have never actually written a "complex" software in C++. There are too many things to think about while writing a piece of code in C++, most often than not, you are bound to get things wrong.
- foo101 9y agoI am not confusing verbosity with complexity and I have written all kinds of C++ software over a career of 15 years ranging from legacy core banking systems to hardware drivers. In fact, the simple C++ code often tends to be verbose. When you are writing complex software, you are bound to get things wrong in any language, not just C++. What I am arguing for is that C++ code need not be complex even if the C++ language itself is complex or the software is complex. If you have an argument against this, please make it substantiatively without resorting to insinuation about the kind of work I do or not do.
- narayanbs 9y agoI apologize if i sounded condescending, and coming from a BFSI background myself, it was such a relief to write software systems in Java after years of C++. I agree "C++ code need not be complex", but the language itself is so designed that most often than not, you end up heading down a slippery slope.
- AboutTheWhisles 9y agoI've written and shipped plenty of software with modern C++. Ownership and move semantics mean that after writing a few helper and utility functions, things go pretty smoothly. The most concise and direct software I've written has all been in C++. I can organize and transform data directly instead of jumping through hoops or suffering from enormous amounts of overhead and indirection in a scripting language. Not to mention I can create stand alone executables that have no dependencies and wind up smaller than most scripting language's interpreters for entire openGL based programs with GUIs. One thing that doesn't often seem to get considered here is what your user wishes you wrote it in. I don't want my software to come as an assortment of scripts that depend on interpreters that themselves might have dependencies. One file is all it has to be.
- HumanDrivenDev 9y ago> Yes, it has a ton of warts if you know where to look. I've never had to go looking to find warts in C++.
- tines 9y agoIt seems like this article is essentially complaining about the language giving you too much control (e.g. in his copy assignment operator example), when that's exactly what its goal is.
- NTDF9 9y agoThere are two kinds of developments: 1. Application level: Typically manipulating lots of strings and data massaging. I prefer Java or python for this. The IDEs and eco-system just is so much faster to start with 2. Systems level: Typically a high-performance system like a DB manager or a fast processing library like a message producer etc. These things are time critical and need performance. I used to really love C++ but I agree, it takes far too long just to start making things run. Sigh!
- notacoward 9y agoThe bullet list near the end closely matches my own experience with C++. There's an inordinate number of features creating an even worse profusion of edge cases where they interact. Then the "solutions" for those edge cases usually add even more complexity. Worse, they force programmers to coddle their compilers. The ratio between what a C++ compiler will accept and what it will produce sane code for is huge. That's why every C++ codebase I've ever seen is full of code to do things that shouldn't be necessary, and goes through all sorts of contortions to avoid doing things that should be OK, lest the compiler spew out an un-debuggable mess. I'm perfectly happy managing my own complexity in C, or avoiding it entirely in Python. C++, on the other hand, seems to have been designed by compiler writers for their own enjoyment and/or job security. Every other "systems programming language" from D to Objective-C to Go to Rust to Nim presents a more coherent face to the programmer.
- clishem 9y agoSure, it's a large and complex language that takes time to master. But I'm interested to hear examples of what you call 'profusion of edge cases'. > The ratio between what a C++ compiler will accept and what it will produce sane code for is huge. As is the case for any programming language. > C++, on the other hand, seems to have been designed by compiler writers for their own enjoyment and/or job security. C++ is designed by its standards committee... If you know anything about the struggles compiler writers have had with implementing the standard, you'd know the standards committee definitely does not consist of compiler writers! It's really cheap to summarize their efforts as motivated by advancing their own job security if you ask me... I can recommend you to attend a meeting or to read some proceedings to convince yourself otherwise.
- repsilat 9y agoDisclaimer: I don't program in C++ day to day, so maybe my experience is atypical. Moves and rvalue references (and whatever a PR-value is) and even RVO scare me. They make me want to pass pointers around, because at least I know for sure what'll happen then. (And, funnily enough, C++ seems worse than dynamic languages for this -- more magic around function calls and returns than C or Python or JavaScript.)
- pjmlp 9y agoWell, most of his points regarding complexity are not C++ specific. The thing with equals applies to most languages that allow to redefine operators. Even Java has gotten quite complex, I bet he would have quite an hard time succeeding at one of those quiz questions certifications (SCJP and friends). And simplicity can also turn into more complexity, manual memory management in C vs C++, "templates/generics" in Go, libraries to work around language limitations in JavaScript (npm, yeoman, gulp, grunt, webpacker all at the same time).
- bogomipz 9y agoThe author states: >Neither the performance issue that move semantics address nor the perfect forwarding problem exist in classic OO languages that use reference semantics and garbage collection for user-defined types." I understand reference semantics but what are move semantics? Also what is the "perfect forwarding problem"?
- thebear 9y agoAuthor here. A few years back, I wrote an article about the issues that you're asking about. Since the article still comes up as the #1 result of Google search for "C++ rvalue references", I believe it's ok for me to recommend it here: http://thbecker.net/articles/rvalue_references/section_01.html http://thbecker.net/articles/rvalue_references/section_01.ht... Warning: Read only if you have a serious interest in C++.
- bogomipz 9y agoThanks, I thought this was well-written.
- deleted 9y ago[deleted]
- KayEss 9y agoPart of the problem here is that OO sits nicely with references, but C++ (like C) is a value based language. This can be seen clearly in most of the design of the standard library -- it's all value semantics, and as such relatively simple and obvious to use (so long as you're not trying to cram OO into it). A line like if ( a == b ) In C++ is pretty obvious what it does. It'll always be a value comparison, and if a and b are pointers to objects you are comparing the object identities and not their values. The meaning is exactly the same in Java of course, but the fact you're dealing with pointers is hidden so you generate a lot of confusion about the correct use of `==` and `.equals`. The author certainly isn't wrong about a culture of complexity in certain elements, but, to be hones, I see that everywhere else too and it needs to be fought wherever it occurs.
- pjmlp 9y agoObject Pascal, Eiffel, Ada, Mesa/Cedar, Oberon, Modula-2, Modula-3, Oberon, Oberon-2, Oberon07, Active Oberon, Component Pascal, Sather, Swift, D, Go, Rust are OO languages[1] and value based as well. [1] - As usual, there are many ways of doing OO, not just C++/Java style.
- IshKebab 9y agoI don't really know about the others but Rust isn't really OO. Neither is Go.
- pjmlp 9y agoSure they are, just not on the classical C++/Java style hence the footnote, as I was already expecting that kind of comments. There isn't "The ONE true OOP way", just like there isn't "The ONE true FP way" or "The ONE true LP way". Each paradigm has a set of concepts of what they might mean, and many languages cherry pick from there. Rust and Go implement polymorphism via traits and interfaces respectively. Rust and Go implement encapsulation via struct methods and modules. Rust and Go implement containment. Rust and Go allow for delegation. Rust allows for type extensions via a mix of generics and traits. Go allows for struct embedding as a kind of type extension. Class based inheritance is not a requirement for a language to be OO. CS literature is full of languages that explored other kinds of OO.
- bjorn2k 9y agoI agree that c++ is complex, but remember that while trying to update the language the standard committee is trying not to do breaking changes. If you can do a greenfield implementation like rust, you don't have the baggage of an installed base, yet. If you compare c++ to a language that is also around for more that 25 years it starts to make more sense why it is complex. Add to that, that it started as an extension to c, which is the reason why it became popular in the beginning. Also, zero-cost run-time abstractions. It is whatever you give priority design-wise, and if you look at what is important in c++ (zero-cost runtime abstractions, control of the resulting code), then ending up with something as complex as the c++ language is hard to prevent.
- IshKebab 9y agoYeah by keeping backwards compatibility they avoided something like the Python 2/3 mess which I would say is worth the effort and cruft.
- lou1306 9y agoOn the other hand, I find Python 3 much more predictable/less astonishing than 2. The jump was definitely a mess, but judging by the continuous spread of the language it seems to have paid off in the long term.
- jVinc 9y agoLooking at the current programming language space, it honestly doesn't look like the Python 2/3 issue hit them that hard in the long run. And while it wasn't popular it might have been the right way forwards. Python is one of if not the most rapidly growing language. In large part due to the data-science movement which for anyone I've talked to is based on Python 3. I still occasionally talk to 2.7 proponents, who explain to me that they need to have this and that to handle all the complicated edge cases and problems in dealing with bytes vs. strings... Issues that you just don't encounter at all in python3. If I had the choice of having a C++2020 with absolutely no backwards compatibility but a greatly cleaned up language or having yet another step down the path it's heading now, I'd chose the former even if it breaks backwards compatibility. But the language is going to follow the developers and they want to continue down the path where they get to explain again and again and again the intricacies and delicacies of rvalue semantics, exotic template meta-programming and what-ever the next big thing is going to be. All the while we seemingly still don't even have a clear road-map for providing simple modules. I was enthusiastic back when C++11 hit and it felt like a great big push going on in the language development, I had the feeling that things were really going to take off... but now it feels like it just died out, and now there's nothing that really gets me exited about the future of C++. I'm worried It's going to get more and more complex and less and less used.
- deleted 9y ago[deleted]
- yason 9y agoWhile my pet peeves might be different than the author's I agree that C++ makes you work very hard to keep things simple and produce something that is beautiful. Just "avoid the complexity you don't absolutely need" doesn't really work: some basic things are so fundamentally convoluted that I rather just write idiomatic C because it's simple and doesn't get in my way. I want the language to originate from simple axioms so that I can concentrate on the complexity of the problem I'm solving instead of wasting brain cycles on battling the complexity of the language. I would like to like C++ but its benefits barely zero out the extra hoops.
- thebear 9y agoAuthor of the blog post here. I think you just made me aware of the true and deeper reason for my discomfort with C++: it's the fact that the convolutions are in the basic things. I am perfectly willing to put up with convolutions, annoyances, bugs, weaknesses etc. in anything I use, be it a programming language, a piece of software, a gadget, whatever. Nothing is perfect, and who am I to criticize others for the imperfections in their work. What annoys me is when the annoyances are in the basic things, in the most commonly used features. Make the basic things reasonably good, and keep the crap off to the side.
- luk32 9y agoI'd be very careful with the claim that you are willing to put up with bugs. Bugs in language or compiler will make the language useless for any project which is expected to work. I'm gonna be bold any say that you nor anyone else would put up with it. There's enough bug in one's own code, there is rarely any space for unreliable infrastructure.
- athenot 9y agoThis reminds me of a goal Larry Wall for Perl when he was designing it: "make the easy things easy, and the hard things possible".
- mannykannot 9y agoI think that one reason the convolutions are in the basic things was the principle that C++ should be a superset of C, which is nominally a value-semantics language, but which, with the use of pointers, very commonly (and intentionally) leads to code with aspects of reference semantics. One example of this is that C++ adopted The C practice in which arrays decay to pointers. In addition, C++ not only inherited C's static-typing rules, but strengthened them, and complicated them with inheritance (multiple, and polymorphic or not, according to your needs), function overloads and operator overloading. Now add generic types through templates, and the cases to be handled explodes to the point where you need a Turing-complete parser. A good case can be made for each of C++'s features individually, which leads to justifications of the form "As we want both X and Y (and without sacrificing run-time efficiency), then there really isn't any alternative to [insert counter-intuitive issue here]..." That it works at all is a testament to the skill of the people involved. The complications that remain seem qualitatively different than the sort of gratuitous inconsistencies that you find in PHP, for example.
- otabdeveloper1 9y agoC++ is not more complex that its competitors like Haskell or Rust.
- tomohawk 9y agoHaving used c++ for many years, this does not come across as a ringing endorsement for looking into Haskell or Rust. I'm quite happy with my current gig using Go. Looking back, the culture of complexity surrounding c++ is obvious, but talking with my peers who have only ever done c++ - it's like they have Stockholm Syndrome.
- tandr 9y agoAny language (or tool for that matter) that you have to invest heavily in, and use for a while will produce a symptoms of "Stockholm Syndrome". Moreover, once you are hard pushed to switch from it to something else, withdrawal symptoms are quite pronounced too. Go has its own share of idiosyncrasies, and it drives me nuts sometimes even more than C++ did, but these bursts of mental grind are less common and much shorter in comparison :). The arcane complexity of C++ (and tooling around it) is something that I don't miss at all.
- PopsiclePete 9y agoI sometimes like to dabble in C++, late at night, while sipping some whisky. For short periods of time. Last night, I decided to "practice" writing iterators. Specifically, I wanted to write a class that i could use in a new-style C++ range loop that would give me all files in a directory. Useless but fun practice, I thought. I had Bjarne's latest book by my side, and the final draft of the C++17 spec in open in a PDF, and it took me a good 2-3 hours of trying before I "got" it. I'm still not sure I'm doing it correctly, btw. It does compile without warnings, and it works, but I can tweak the iterator function signatures in seemingly incompatible ways and it still doesn't complain and still works, even when I swear it shouldn't. "Ok, surely by doing this I'll break it!" - nope, still works. I don't love everything about Go, and once in a while I'll wish for more expressiveness, but I was never, ever, as 10% confused with it as I am with whenever I attempt to do something seemingly trivial in C++.
- ndh2 9y agoLots of posts here frame it like "Yes, it's a bit of a complex language, but the C++ committee has the difficult job of keeping everything backwards compatible, so it's understandable." But that's not the reality. The reality is that they (or Stroustroup) made that decision, and that decision was a mistake. The correct way to deal with backwards compatibility issues is the way Go does it, namely to write tools to automatically upgrade code to a newer API [1]. And as that smug Google guy explained here [2], they have something like this for C++, too. They just don't bother sharing it with us peasants. The fundamental mistake of C++ is to religiously keep backwards-compatibility with everything for all eternity. It's so easy to say that backwards-compatibility is a good thing. It's obvious! But ultimately that decision is the reason for all the problems that C++ has. [1] https://golang.org/cmd/fix/ https://golang.org/cmd/fix/ [2] https://www.youtube.com/watch?v=tISy7EJQPzI https://www.youtube.com/watch?v=tISy7EJQPzI
- gpderetta 9y agoBackward compatibility with C semantics and tooling was fundamental for C++ success. We wouldn't be having this discussion otherwise as nobody would have used C++. Tools are great for minor upgrades of APIs and syntax, but key to C++ was compiling with existing system headers (no, realistically you do not want to maintain your own 'fixed' version), and most importantly OS and library ABI.
- pjmlp 9y agoAT&T had a Java like variant of C, before Java was even a thing, called C+@. This DrDobbs article in an 1993 issue dedicated to possible successors to C, is the only proof that it ever existed. http://www.drdobbs.com/article/print?articleId=184409085&siteSectionName=cpp http://www.drdobbs.com/article/print?articleId=184409085&sit... Print view is the only way to read it properly.
- ndh2 9y agoI agree. I said that it was a mistake, but in the beginning it really wasn't. It's just not a viable long term strategy in my view.
- 9y ago
- neo2006 9y agoThe author is relating a personal experience As a former C++ dev I saw some wonderful code base written in Ç++ and some horrible code base, as any other language. The only specifity Ç++ have in my opinion is that some features have a high learning curve and are not necessary shared with other languages. Once you mastered Ç++ it's easy to move to other languages but it's hard to do the reverse path.
- andrepd 9y ago>Rvalue references provide move semantics, and they solve the perfect forwarding problem. Neither the performance issue that move semantics address nor the perfect forwarding problem exist in classic OO languages that use reference semantics and garbage collection for user-defined types. I don't get this. The performance issue move semantics solve doesn't exist if you just use automatic garbage collection? Is this what the article is saying?
- gpderetta 9y agoThose specific issues do not obviously exist if the language lacks value semantics. Other issues of course do exist, namely allocation overhead and pointer chasing and the difficulty of doing escape analysis.
- sevensor 9y agoWhen I was young, I thought I understood C++, because I had been taught it in school. I did not. Having interviewed several recent graduates who thought they knew C++, I believe this is fairly common, particularly among people with advanced degrees in engineering and the sciences. It's very easy, in C++, not to know the scope of one's ignorance.
- int0x80 9y agoThis is very true. I've seen very ignorant (on c++) people say that they dont find c++ complex at all, but very simple. Most of the time this only shows the lack of deep knowledge on the language.
- pjmlp 9y agoYou can do the same with someone that says C is easy to master. Just pick a copy of ANSI C and randomly ask a couple of UB questions. You have a catalog of about 200 cases to chose from.
- beached_whale 9y agoI think it depends on where you sit on the stack. A library can take a lot of the complexity away from the higher levels in C++ code. The user code can look fluent and understandable. On the implementation side of the library being used(depending on where it sits in abstraction) is where some ugly complexity shows. But this also generally reflects the competence of the authors.
- humanrebar 9y agoOn the other hand, it's hard to grab a half dozen C++ libraries off the shelf and just use them together without issues.
- beached_whale 9y agoTrue. That is getting better though and lots of people are putting time into solving that. It's tricky because no one is talking about the same thing either. Like my project structure isn't your's. It's not byte code so distributing binaries is a crappy problem too. I am of the mind that a dependency system above the build system(s) is probably the best bet. Not as low level as binary interface, but I need libary X >= version n.m.o...
- carapace 9y agoI think there's a "sweet spot" in complexity (at least for software): too complex gets rejected, but being too simple lacks traction. I think artifacts like C++ memetically infect the brain better than a more elegant PL might, exactly because they require you to think about them a lot, but you can still get things done and not be (totally) overwhelmed.
- petters 9y agoI like the fact that in C++, the line x = y; behaves the same if the types are int and vector<int> (unlike e.g. Java and Python).
- mar77i 9y agoIsn't there anyway some of a pendant to Conway's law in this? I mean, C++'s standard library is - or at least used to be - rather complex, so the people that would go there and use C++ for their project - would more likely than not - carry at least some of that complexity over into the project...
- geoffroy 9y agoDoes anybody know a good tutorial or book for learning modern C++ 17, focused on best practices (new language paradigms, TDD/BDD, etc.) ? Something like Michael Hartl's Ruby on Rails Tutorial
- pfultz2 9y ago> What does that do? It makes the variable x refer to the object that y is referring to In Java/C#, it doesn't always: int x = 1; int y = 2; x = y; The variable `x` does not refer to the object that `y` is referring to(as there is no reference involved at all). Assignment is a procedure that makes `x` equal to `y` without modifying `y`. However, if `x` refers to `y`, then we can modify `y` after assignment to `x`. This destroys the ability to reason locally about the code, because each object essentially becomes as good as a global variable. Even though C++ has areas where things gets complicated, this is the one thing that C++ keeps very simple and consistent. There is only one definition of copy, assignment, and equality, whereas in java there is multiple definitions(deep copy vs shallow copy, `==` vs `.equals`). > That’s called value semantics, although I would prefer the term state semantics: objects do not have a value, they have state, and that’s what’s being transferred here. No. Its value semantics, as these objects represent some entity. The interpretation of the state(or datum to be more precise) is the known as the object's value. For example, when copying a `std::vector` the internal state of the vector will be different on copy, as it will point to new piece of memory, however, its value will still be the same. > But experience shows that making a copy of an object is hard. The compiler already generates a copy constructor and assignment for you. Its only necessary to write one, when one is dealing with low-level pointers. Using the standard built-in types and containers, writing a copy constructor is never needed.
- commandlinefan 9y agoWell, if you haven't encountered any brain-bending Javascript, you haven't gotten very far into Javascript.
- Animats 9y agoOne word: Boost. C++ went off into template la-la land some years back. C++ templates were not supposed to be a programming language. But they turned into one, and not a good one. Look up the implementation of "max" and "min" in C++ templates. Now there's a push for "move semantics", to keep up with Rust and the cool kids. But not with language support and a borrow checker. With templates and cute tricks with the type system.
- jokoon 9y agoC++ is the only language that is compiled to binary, compatible with many compilers and OS, and can do both low and high level constructs. It is true that it is a complex language, but this is true for every tool that allows you to do so many different things. The complexity is not a goal in itself, it's just that it can do all of those things if you need them. Simple tools are great and will save you a lot of time, but the truth is that you won't always be able to do everything with them. C++ allows you to do everything, and it is true that the cost can be very high and requires a lot of thorough knowledge and expert learning of what happens, but there are projects and cases where you just need to use C++ because that's the only choice you have left. I agree that an alternatives like rust or D would be great as replacements, but the problem remains: if compilers are not mature on most platform, and if you don't have a large programmer base because the basics of the language are not simple enough, the language won't grow.
- steveklabnik 9y agoRust uses LLVM, so we share the same characteristics here as clang does.