15 ms·
You can't make C++ not ugly, but you can't not try (2010)
- gumby 7y agoThis decade old article describes an ancient and obsolete language (C++03 probably though some of the text suggests it might be C++98). It's not worth reading in 2020. Modern C++ is a very different language though it can still almost completely interoperate with quite old code. C++11 and C++14 already addressed most of the things brought up, and contemporary C++ (obviously most code is not in it yet) even supports generic template functions with a straightforward syntax (i.e. use auto instead of <..>).
- JonathonW 7y agoThe author also seems to really, really want C++ to be Python, despite that they're completely different languages for completely different purposes that make completely different sets of design tradeoffs. In that respect, the author probably wouldn't be happy with modern C++, either. For example, C++ is never going to be a garbage-collected language (by default, at least). Modern C++ gives you better tools to deal with that, but the core design concerns that make C++ the way it is haven't gone away.
- Someone 7y agoI’m not aware any exist, but implementations of C++11 can have garbage collection by default. https://isocpp.org/wiki/faq/cpp11-library#gc-abi https://isocpp.org/wiki/faq/cpp11-library#gc-abi: ”Garbage collection (automatic recycling of unreferenced regions of memory) is optional in C++; that is, a garbage collector is not a compulsory part of an implementation. However, C++11 provides a definition of what a GC can do if one is used and an ABI (Application Binary Interface) to help control its actions.”
- deaddodo 7y agoThat's not "by default". The compiler doesn't provide it, the language provides for you as the developer using the language to implement your own (or use a third-party) GC and utilize it. D and Rust both offer the same amenities and are not "garbage collected" languages.
- kllrnohj 7y ago> D and Rust both offer the same amenities and are not "garbage collected" languages. Rust isn't but D is absolutely a garbage collected language. The GC is provided by default and expected to exist. https://dlang.org/overview.html#resource https://dlang.org/overview.html#resource & https://dlang.org/spec/garbage.html https://dlang.org/spec/garbage.html There's a non-GC'd subset of D, though. That would be the BetterC subset https://dlang.org/spec/betterc.html https://dlang.org/spec/betterc.html
- bachmeier 7y agoI think it's more accurate to say D's GC is expected to exist if you want to use the full language. That's sensible, because the option to use GC makes some things practical that otherwise wouldn't be. You can disable or simply avoid the GC, and you can add @nogc attributes to your code if you want to be certain there won't be any GC allocations. BetterC certainly does guarantee there's no GC, but that's a limited (for now at least) subset of the full language.
- dfox 7y agoThe quote seems to be about the compiler/environment being permitted to offer GC, ie. permits you to write C++ implementation on top of some GC'd runtime. It does not say anything about you as a language user having enough introspection capabilities to write an GC. As a side note it seems that one can (ab)use smart pointers enough to build essentially working tracing GC on top of that, I've seen that done and well, the performance is horrible, obviously.
- pjmlp 7y agoActually C++11 introduced a GC API.
- gpderetta 7y agoIt seems to me that just a couple of do nothing placeholders were added to please Hans Boehm and get him to work on the c++ memory model :).
- pjmlp 7y agoEven so, there are the .NET, Unreal and COM/UWP programming models as well, which while not taking advantage of C++11 GC, do bring a GC into C++ world. :)
- downerending 7y agoYou wish. Unless I'm terribly misinformed, "modern C++" contains all of the features of the prior versions, which means that in the real world you have to learn and deal with all of it.
- jfkebwjsbx 7y agoThat is the point of backwards compatibility. It is a feature, not a bug. Whether that feature is a good idea or not and to what degree, is the question.
- Quekid5 7y ago... but it's worth considering that this is a 'question' from 2010. Just saying...
- downerending 7y agoI'm not saying it's a bug. I'm saying that backwards compatibility means that you still have to deal with all of the historic flaws of the language today. The article is indeed still relevant.
- UncleMeat 7y agoBut that’s true for literally everything. If you have a cpp code base and are building new stuff in rust to interop then you still have legacy cpp code even though rust has fewer problems.
- KptMarchewa 7y agoNot really. Legacy stuff can be contained. For example, you could specify language version level in file and it would disable removed/deprecated stuff.
- UncleMeat 7y agoLinters can prevent you from using outdated C++ constructs with ease.
- carterehsmith 7y agoSure, "if" all of that old code (how many billions of lines of code?) was rewritten and redeployed since. If not, then... the above statement does not stand.
- Rusky 7y agoTo the contrary, modern C++ has solved very few, if any, of the problems described in the article. Being generous: * There's now `std::string_view` to address some of the problems with `std::string`, but the rest are still there. There are some attempts to specify the encoding now, at least. * Lambdas and `std::function` pretty much solve the function pointer complaints, with some added complexity. * Containers still do silly things when you use `c[..]` syntax with no element there. (Both when trying to insert and when trying to retrieve!) * The general level of language size and complexity, especially around templates, has only gotten worse. Concepts will finally help in some ways here.
- UncleMeat 7y agoI think most people agree that operator[] is a big footgun for containers, but rigorous use of const helps at least prevent surprises.
- gumby 7y agoAnd operator new is hardly used any more in modern C++ code.
- cmroanirgo 7y agoIf everyone can forgive my ignorance... I used to call everything in the std:: namespace as just that, the standard template library (STL) (whatever it's iteration). So is this C++03 /C++11 stuff just updates to this library, or is std::string recognised at the compiler level? (Genuinely confused). (In old man voice) We ended up rolling out own stuff and marking std:: verboten. Why? Stl was too slow, too verbose, and too hard to grok the stack when debugging. We ended up with less memory fragmentation, less dangling ptrs, etc etc. In the rare case there was something in STL that was actually cool (or faster, which was very rare), we'd gut it and reef out the part that was cool to use in our implementation. I presume these comments aren't popular (sorry about that, but this is during 90s and early 00s when dev cycles were clearly different). Eg. We had string classes in all different flavours, some would interop, some wouldn't. Eg. We had tree and hash classes that, while templateable, had a few core implementations that made compilation fast. We had various ptr management systems (ref counted, stack based, etc). We made STL between verboten in all APIs because we been burnt so many times using (/trying to use) other ppls APIs that exposed STL in its library. (We were exclusively a windows shop, if that helps understand my confusion... PS. I'm retired these days and have been out of the c++ game >10yrs)
- kevin_thibedeau 7y agoSome of us still have to use outdated C++ compilers where the ::std namespace doesn't exist and all the modern goodies are but a dream.
- nmeofthestate 7y agoTrue - some of the specific problems have been handled, but C++ is still kind of a disaster. The language has got even more complex in many ways. Some coders like that and get really into understanding the byzantine complexities, so the codebase inevitably gets dragged into unmaintainable, hard-to-debug cleverness. From my experience, C++ development is getting better, largely because tools are getting better at hand-holding and pointing out all the foot-shooting mistakes you can and do easily make on pretty much every line. Maybe C++30 will have fixed everything...
- kazinator 7y agoC++11 was just around the corner then, in draft form. The article shows awareness of it.
- Quekid5 7y agoI certainly agree that Modern C++ is vastly bett... actually this is just someone posting an old polemic and trying to stir resentment/controversy. IGNORE THIS CRITICSM OF C++... there are much better and more relevant ones which are worth taking seriously. This is not worth taking seriously. (I wonder how many of these posters are real or fake. Given the karma and post of this poster I'm inclined to... wait. Last comment was in 2017. Yet... hasn't too many posts since that, I think it's about 4. Probably a bit out of the loop, buy maybe not malicious.)
- DenisM 7y agoFrom the rules: [...] Please don't post insinuations about astroturfing, shilling, brigading, foreign agents and the like. It degrades discussion and is usually mistaken. [...] https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html
- Quekid5 7y agoThat's fair... but how exactly are we to call out these abuses otherwise? (Without having a trivially traceable e-mail address.) Maybe it's an idea for a new "button" other than spam/flag/etc.. FWIW, I think I backed up my accusation adequately for at least a mod review. EDIT: To be even more meta... I sense a certain pattern in your comments, sir. What gives? EDIT#2: Love your retaliation by downvoting totally unrelated comments, btw. Wtf?
- DenisM 7y agoThe rules I have previously posted contain the answer to your first question.
- Quekid5 7y agoEDIT: Please don't be opaque about this stuff. Post an exact link to the ToC (or whatever) I violated if you truly want to be held accountable. I'm not even on a I-want-to-an-a-hole crusade here[0], but HN has a serious lack of accountability and transparency about this. I contend that it's full of shills, but I have yet to prove that, which I acknowledge. Anyway, I flagged it. I'd delete my post if I could. Wait, I actually still could. That still doesn't account for the downvotes I just received on random comments unrelated to this topic. If I deleted it would that delete causally-related-downvotes? [0] As you can hopefully tell from from my comment history. EDIT#2: Can I "report" you... and if so, how? I'm not going to, but could I, theoretically? That's a good test for accountability.
- dana321 7y agoC++ is mostly an abstraction layer over C. I would rather use C++ because i would have the option to use abstractions like std::map, std::string, std::vector, std::any etc. as they would save a lot of time and code complexity. IMHO the worst thing about using C/C++ is getting other libraries to play with your project well even if you are using cmake or vcpkg, its not enough. You have to have solid knowledge of each operating system class to get everything working nicely over the long-term.
- saagarjha 7y ago> C++ is mostly an abstraction layer over C. That depends on how you write it. It’s possible to write C++ that bears no semblance to C whatsoever. (I have done so for effect; I once assigned some students to write a C program but wanted to provide a reference implementation with source so I gave them one in C++ that wouldn’t translate directly at all.)
- dana321 7y agoInternally, i mean, thats how it was originally built and it generates code much in the way that C would, if you would have manually coded it. Maybe not jump on my head without thinking first!
- saagarjha 7y agoNot trying to jump on your head; I apologize if you got that impression. But while C++ was originally C preprocessor/transpiler, modern C++ has diverged quite a bit from from this. I mean, take a look at this and tell me how it would be possible to convert it to C in a straightforwards way: https://github.com/regular-vm/libencoding/blob/master/encoding.h https://github.com/regular-vm/libencoding/blob/master/encodi...
- dfox 7y agoFor me the main issue with C++ is the idea of no overhead for features you don't use which is not bad idea, but is complete nonsense when the measure of “overhead” used by the language authors is some combination of how the hypothetical C code generated by hypothetical cfront behaves and how the resulting code would run on early 80's minicomputer...
- unlinked_dll 7y agoMost of what the author complains about w.r.t callbacks is fixed with std::function and lambdas (member function pointer syntax is necessarily weird, because methods aren't just normal functions). I definitely don't miss the days of std::bind. Nowadays you just do something like using Callback = std::function<int(int)>; // or whatever Callback cbk = [&](int i) { return instance.method(i); }; I've also seen some real evil hacks that rely on casting 0 as a pointer to a class and relying on the ABI's spec for vtable layout to calculate the pointer of the function as an offset from the `this` pointer. Because that's easier to remember than the syntax for pointer-to-member functions.
- a_t48 7y agoThere's also Callback cbk = std::bind_front(instance, Instance::method); in C++20. I'm going to ignore std::bind as it has weird conventions. :)
- PaulDavisThe1st 7y agoUsing lamdba's requires grappling with entirely new syntax compared to anything else in C++ (or C). Using various bind equivalents just requires you to know what you're doing: boost::function<int(int)> cbk = boost::bind (&SomeObject::some_method, instance_of_some_object); ... cbk (22); // invoke callback In addition, the author's complaints about nobody using ptr-to-method is absurd. Even in 2010, anyone using libsigc++ or its (few) equivalents was using them, which meant that any GUI app written using GTKmm was full of them. What's not to love?
- AnimalMuppet 7y agoWhat's so awful about pointer to member? I've used it a couple of times, and didn't think it was particularly weird. I mean, yes, I had to look up the syntax, but it was rather straightforward.
- gpderetta 7y agothere is nothing wrong with them, but pointers to member do not close over this, so you still need some form of binding to use them as callbacks.
- Ar-Curunir 7y agoThe followup article (https://apenwarr.ca/log/20100721 https://apenwarr.ca/log/20100721) talks about a potential C/C++ replacement, and seems like a lot of points match up with Rust
- deleted 7y ago[deleted]
- Quekid5 7y agoThis is (robo?) spam (try the 'past' link), and the user should be permabanned. Sad to say, but...
- dang 7y agoThat's inaccurate. Not only are reposts fine after a year or so (see https://news.ycombinator.com/newsfaq.html https://news.ycombinator.com/newsfaq.html), we invited this repost. We do that sometimes: https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=by%3Adang%20invited&sort=byDate&type=comment https://hn.algolia.com/?dateRange=all&page=0&prefix=false&qu.... Please stop posting like this to HN.
- asdfasgasdgasdg 7y agoThat C code wouldn't work if the strings in the map are mutable (which they are in C++). It wouldn't work if the strings were allocated dynamically either. Once you write all the code required to get it working that way, the C starts comparing less favorably to C++.
- fctorial 7y ago> That C code wouldn't work if the strings in the map are mutable (which they are in C++). It wouldn't work if the strings were allocated dynamically either I don't see why not? You'll have to decide the ownership semantics if they're dynamically allocated but that's it?
- AtlasBarfed 7y ago"C++ isn't a language, they say, it's a language construction kit! Build the language of your dreams in C++! And it'll be portable and scalable and fast and standardized!" This is the power and achilles heel of Lisp as well.
- nineteen999 7y agoDifference is, C++ actually has more than single digit mind/marketshare outside the safety of the HN eggcup.
- TheOtherHobbes 7y agoMarket share, maybe. Mindshare - Lisp has its zealots. C++ is tolerated rather than adored, because it's more of a Katamari Damacy of stray CS than a language with a coherent focus. How many other languages have a Turing complete sublanguage built into them just to handle templating?
- nineteen999 7y ago> How many other languages have a Turing complete sublanguage built into them just to handle templating? On the bright side, C++ doesn't have obscure keywords like "cdr" and "car" that refer to specific hardware elements of an obsolete computer built in 1954.
- ridiculous_fish 7y agoNope, only trap representations, in case you are using an Itanium for some reason.
- nineteen999 7y agoTrap representations are an abstraction though, even if IA64 is one of the very platforms where they are used. CAR and CDR are literally named after CPU registers of the IBM 704.
- dathinab 7y agoDidn't got much better since then with regard to that aspect. IMHO C++ tried to adapt many features which had shown succesfull since then, but instead of properly putting them into the language they often got implemented in a way which I would describe as "somehow hacked in to try to avoid to actually introduce new features" but others might describe as implemented in a very C++ish way in symmetry to other features. Anyway the result is often sup-par. Not downright shit but worse then it should be and more important making the features work less good (from a complexity+usability POV) then in the languages they where copied from.
- _wldu 7y ago"About the same time we were starting to work on Go, I read, or tried to read, the C++0x proposed standard and that was convincing to me." -- Ken Thompson Source -- https://www.youtube.com/watch?v=sln-gJaURzk https://www.youtube.com/watch?v=sln-gJaURzk
- crazypython 7y agoYou can make C++ pretty: it's called D. https://dlang.org/comparison.html https://dlang.org/comparison.html Here's the D<->C++ intercompatibility project: https://wiki.dlang.org/Calypso#Current_status https://wiki.dlang.org/Calypso#Current_status
- coding123 7y agoThere's always a D guy lurking about.
- WalterBright 7y agoWe're everywhere.
- coding123 7y agoWhoa!
- deleted 7y ago[deleted]
- pizlonator 7y agoI love programming in C++ and I love this rant. If you ever design a language you should hope that it gets popular enough that people bitch about it this hard. That’s a real triumph.
- cryptonector 7y ago> But in python, it works perfectly (even for > user-defined types). How? Simple. Python's parser > has a little hack in it - which I'm sure must hurt > the python people a lot, so much do they hate > hacks - that makes m[5]= parse differently than > just plain m[5]. > > The python parser converts o[x]=y directly into > o.setitem(x,y). The name for this is "generalized variables", at least in Lisp land. The idea is to allow complex assignment left-hand side (LHS) expressions and turn assignments into calls to setter functions, including whatever complex data structure traversals might be needed. Lisp has generalized variables via "setf macros", which turn assignments into the right set of calls to setter functions. Setf macros do this at compile time and generically for any getter/setter functions that have been registered with a bit of ceremony. (Lisp also has destructuring-bind, which lets you write a data structure with variable symbols in it such that the corresponding variables will be bound to the data find in the corresponding places of a real data structure value. The two features, destructuring and generalized variables, are similarly magical.) jq can do crazy generalized variable assignments like '.a[].b[0] = 1', but this is a run-time thing. (The LHS is evaluated in a context that allows only "path expressions", and in a reduction, while the RHS expression is run in the body of the reduction to update the input value at each path matched by the LHS.) Icon implements generalized variables by letting procedures return "places" -- references to assignable locations --, so you can assign to the return value of procedures. This may seem quite surprising when you see it, but it works beautifully.
- rkv 7y ago> No support for null strings? Check Why would you ever want this? Gives me Java nightmares.
- MrBuddyCasino 7y agoApenwarr‘s comment to this thread: „ I have since stopped trying to program in C++ at all. C is still ok, sometimes.“ [...] „I want to like Rust; maybe someday.“ https://twitter.com/apenwarr/status/1232848468156256256?s=21 https://twitter.com/apenwarr/status/1232848468156256256?s=21
- ggambetta 7y ago[The [] operator] is an absolute failure of engineering! Do you want to know what real engineering is? It's this: map_set(m, 5, "foo"); char *x = map_get(m, 5); So like map::insert and map::at? Did these not exist in 2010?
- pjmlp 7y agoThey did.
- sarabande 7y agoReplace the two double negatives and you get a better title: "You can't make C++ beautiful, but you must try."
- virtualritz 7y agoI recently picked up a C++ codebase I wrote maybe 30% myself and which was last touched in 2013. It's a plug-in for a DCC app. The 3rd party API it communicates with was changed so refactoring was inevitable. Before I started refactoring I decided to make everything 'less ugly' by moving it to C++17. Which would also help me get back into the code, after eight years. I spent two days on this. Then I decided: fuck it. I will RIIR™.[1] It will mean that it will take me at least two months to get a beta of the product with feature parity vs. maybe a week to port the old codebase to the new API. But on the other hand the C++ code is littered with stuff that 'just works' but can explode in your face and which eventually needs some safety net written around it. Which will likely take at least two months to do properly. The truth is: after one and a half years of Rust C++ feels painfully ugly. For context: I started with C++ with Borland's TurboC++ (moving from C) when I was 15. I used C++ for almost 30 years by now. It's about time. [1] Yes, I did read http://adventures.michaelfbryan.com/posts/how-not-to-riir/ http://adventures.michaelfbryan.com/posts/how-not-to-riir/
- gpderetta 7y ago> The problem is that the default C++ string class is so utterly godawfully stupid. No garbage collection? Check. No refcounting? Check. the irony is that in 2010, many std::string implementations were in fact reference counted (including libstdc++). This was generally considered a major mistake (because it doesn't work well with threads and when it does is a major performance pitfall) and prohibited in C++11.
- diegoperini 7y agoCan a native English speaker kindly explain the title? With that many negative tenses, it's really hard to parse the motivation of the author.
- jimktrains2 7y agoIt's in the vein of "even if you can't do something, you should to try anyway" Not ugly is more of a less strong "pretty" and can't not is more of a "should" (rather than "can"), so the title can be read as "you can't make c++ pretty, but you should try (to make it pretty)".
- diegoperini 7y agoThanks!
- ____Sash---701_ 7y agoYou mentioned that there's no standard string class for c++, and that python is your goto, would recommend looking at Dart Lang, extension methods have recently been added, it also compiles to native exec binaries. https://dart.dev/ https://dart.dev/
- deleted 7y ago[deleted]
- trewr234234 7y agoThe biggest issue with C++ for me is the confusing memory model. You have smart_pointers, you have move semantics, and then you have libraries like OpenCV doing their own refcounting (and also using std::shared_ptr). The C++11 features like lambdas are definitely welcome but at this point C++ epistemic footprint is just too large.
- sagarm 7y agoI 100% agree with the title, but some of the complaints in this article have been addressed since the article was published by C++11, C++14, or C++17. Others are just weird. > If you've heard anything about C++, you've probably heard that there's no standard string class and everybody rolls their own. Is this still true? std::string seems perfectly reasonable now, especially now that they've given up on supporting ropes and integrated the small string optimization. Yes it doesn't specify an encoding. > No garbage collection? Check. No refcounting? Check. Need to allocate/free heap space just to pass a string constant to a function? Nothing else in the standard library is garbage collected or refcounted by default. Why would std::string be the lone exception? You can opt into refcounting for any type using std::shared_ptr. The objection about allocating/freeing heap space is about APIs that take const std::string& being passed C-string literals. Legitimate complaint, but it's addressed by std::string_view now. > ...rant about lack of []= operator... [] mutating the map does surprise people, so that's definitely a legitimate complaint. And it is annoying to have to use find() in a const context... but simple operations like counting are simpler and more efficient in C++ than in Python because the +=, -=, etc operators work: for value in list: counts[value] = counts.get(value, 0) + 1 vs for (auto& value : list) counts[value]++; > So actually C++ maps are as fast as python maps, assuming your compiler writers are amazingly great, and a) implement the (optional) return-value optimization; b) inline the right stuff; and c) don't screw up their overcomplicated optimizer so that it makes your code randomly not work in other places. This is just comical. Python is not playing in the same performance league as C++, regardless of whether inlining or RVO happens. RVO of course is a general optimization for returning objects by value from functions, not a special case to optimize setting map items. It's still relevant, but less important since C++11's move semantics.