10 ms·
> I used C++ inheritance, templates, exceptions, custom memory allocation and a bunch of other features I thought were very cool at the time. Now I feel bad for
by haberman 14y ago
> I used C++ inheritance, templates, exceptions, custom memory allocation and a bunch of other features I thought were very cool at the time. Now I feel bad for the people who have to maintain it.
I think this is right on the money. There are a lot of things you can do with C++ (and other languages -- even C probably) that feel good at the time, only to learn later that they don't age well.
I've never seen it analyzed deeply why this is, but I suspect it has something do with how "fungible" the code is when you're done. Will your design let you make small design changes with relatively small and localized code changes, or has your complicated template/inheritance-based design "locked up" your code into a particular pattern, where changing any of the design assumptions requires "unwinding" a highly intertwined structure?
I don't know the rigorous answer to this question, so I design with various heuristics, which mostly boil down to some version of "this is getting a bit too complex or too highly leveraged." What I mean by "leveraged" is that some significant guarantee or invariant is achieved through a complicated contract between two different objects. I try to keep the design of every individual type/object as "flat" and unsubtle as possible; again vague terms, but I know it when I see it.
- ggchappell 14y ago> ... I suspect it has something do with how "fungible" the code is when you're done. Will your design let you make small design changes with relatively small and localized code changes, or has your complicated template/inheritance-based design "locked up" your code into a particular pattern, where changing any of the design assumptions requires "unwinding" a highly intertwined structure? I'd say that this is right on the money. I think it is true that hardcore OOP (along with similarly complicated constructions) gives benefits to the designer who chooses a good and appropriate structure. But, due to the idea you mentioned, it severely penalizes even mildly poor designs, or designs that need to change.
- api 14y agoI think hardcore OOP is highly overrated outside of a few use cases where it does seem to work well: graphical user interfaces and certain kinds of business logic. In those two cases, OOP works because it correctly models the underlying problem. For GUIs for instance: A window is an object, a button is an object contained within a panel that is an object contained within a window... and so on. All of these are "drawable," and can receive mouse clicks, etc. OOP models that well.
- tomp 14y agoI think that anything that OOP models well could be modelled even better with interfaces/traits, especially in flexible languages such as Go. To me, OOP is mainly useful for implementation inheritance (in the rare cases where it's really needed). A very nice example is Python - it allows, but doesn't force you to use objects. I only use objects for encapsulation (e.g. make a new random number generator that is "independent" from the application's main RNG), and I don't recall ever using inheritance (in Python).
- api 14y agoI'm using C++ right now but tend to write very "thin" C++ that is mostly C-like. I just like the object syntax for grouping things together, I sometimes do use a little bit of templates/inheritance when it makes sense, and I like the STL core data structures. C has nothing like STL -- no good portable data structure library. (STL isn't that great, but it's passable and ports to everything.) Operator overloading is nice in places, like with data structures and for mathematical code, but should not be over-used. Exceptions can also be useful, though in my current code base I am not using them much. Boost is somewhat tempting but it's just too convoluted in places. Haven't had a reason to use it yet. Qt is nice for GUIs. The thing about C++ is that it's a language that lets you do almost anything, and it has no stylistic traditions. It's like Linux if it has absolutely no filesystem layout standard or LSB. Each C++ sub-community (Microsoft, Qt, Boost, etc.) has its own conventions that are in conflict with one another. The language imposes no internal sense of discipline and carries no de-facto coding standard. As a result, I find most C++ libraries to be annoying to use even in my own C++ code. I tend to use it as a top abstraction layer gluing together underlying C libraries and system calls, and to use most C++ libraries (except STL) reluctantly. It's too bad... well-done C++ can be very clean, efficient, and safe from things that dog C such as memory leaks, buffer overflows, or rare core dump crashes due to things that could be caught and handled as last-resorts in a try{} catch ( ... ) {} construct.
- hosay123 14y agoIn my experience there's only 3 major C++ styles: BusinessObjects *(Java-ish Qt), std::cavedwelling<stl_guru, guru_cavedwelling_tag<const _Type<T &> >::const_value_type, and void _rather_be_writing_c(); Often code you'll come across is some combobulated identity crisis mixture of those 3. In terms of sheer readability and extension, I'm a major fan of Qt's design style (their most elaborate use of C++ appears to be virtual functions and the pImpl idiom), although that approach leads to heavy heap usage. Really detest simple problems "overly" expressed in guru-ified STL. Can't read it, can't modify it, can't extend it, can't debug it. Naturally this means I'm not a great fan of Boost.
- eropple 14y agoCan't read it, can't modify it, can't extend it, can't debug it. Naturally this means I'm not a great fan of Boost. The STL in particular is designed the way it is largely for performance reasons. Ditto for Boost. I am not a fan of writing template soup, but theirs has a purpose. I mean, it can totally be frustrating (the inheritance hierarchy for collections/iterators recently gave me grief), but the reasons for their design decisions, when you take into account their goals, are generally very sound. In any event, I have never had to introduce template soup to my code when using Boost. Even the boilerplate annoyances have been largely mitigated with C++11 and type inference.
- minimax 14y ago"There are a lot of things you can do with C++ (and other languages -- even C probably) that feel good at the time, only to learn later that they don't age well." I think this reduces to the argument that you should do the simplest thing that works. As a programmer (especially as a C++ programmer), it's tempting to write clever code. It's fun. Why do something the boring straightforward way when you can invent an elaborate class hierarchy, or use that CRTP thing you keep reading about? Being a good C++ programmer requires a certain amount of discipline, but I think that's a trait that's helpful with more modern languages as well. Consider languages that allow monkey patching. It's a neat feature, but if used without discipline will lead to code that doesn't age well because it imposes more complexity on the codebase.
- megrimlock 14y agoIt's tempting because that's how we build our skills. You must abuse a tool to understand it, and know when to not use it. Unfortunately in professional contexts, many of us do that learning on the job, exhausting out a turbulent jet wake of too-clever code, upsetting those who follow. Coming across CRTP for the first time is either an upsetting detour or a fascinating David Foster Wallace style WTF-inducing endnote that you must consume before continuing. You appreciate this dynamic more as you play out different roles, both producing and consuming. Some languages try to interdict this state of affairs, shielding us from each other, but the more fun languages let us burn ourselves and our colleagues and finally learn restraint in ways you never learn in languages with training wheels.
- cageface 14y agoThis is like insisting on driving around in a horse-drawn buggy because a car can crash at higher speeds. At this point I just ignore anybody trashing C++ that isn't offering any real alternatives. And no, C isn't an alternative for large scale app development.
- Nursie 14y agoIt's true, nobody ever wrote a large scale app in C. Ever.
- ttflee 14y agoIMHO, you missed the Linux kernel(, OK, it's kernel and does not count as an app).
- jlgreco 14y agoI suspect Nursie is being sarcastic.
- Nursie 14y agojlgreco is correct, that was deep and sincere sarcasm on my part. C is an extremely capable language and I personally have (technical, not people) managed millions of lines of it. I really don't understand the mentality that C is hard, that memory management is hard, that pthread-multithreading is hard and that complex systems in C are impossible, But then I've been coding in it professionally for about 12 years, so I guess I just grok it.
- npsimons 14y agoWhile I agree that limiting to a subset of C++ and keeping it maintainable is a good thing (I regularly argue against using things in C++ so that the cognitive load will be lower), I have to say that if templates are locking your code into a design, you're doing it wrong. Maybe I've not abused templates enough, but every time I've applied them, it's always made my designs more flexible.
- rayiner 14y agoC++ code doesn't "age" well. Linux kernel C code basically looks like UNIX C code from 25 years ago. C++ code from the mid-1990's is all about OOP, then it was STL containers and RAII, then it was template metaprogramming, then people scaled back on that because it was incomprehensible, and now it's boost and smart pointers, etc. Moreover, because the various features are all fairly incompatible, you really have to think about how you want to design something before putting it down on paper. Were you passing around STL vectors of objects to take advantage of RAII? Well, hope you never want to create sub-classes and use polymorphic methods because then you'll have to change everything around to store pointers instead and change all your '.' indirections into '->' indirections. Oh wait but that fucks up your memory management, so you better change everything to use smart pointers and hope nobody ever memcpys the arrays instead of using std::copy. C++ is a mish-mash of features that don't really work together. The only guiding principle I can really see is: "is it cheap to implement?"
- dakimov 14y agoIndeed, C++ does neither have a comprehensible established paradigm of coding style, nor a consistent coding culture, as e.g. Java or C# do. It is very sensitive to the professional and personal qualities of a particular developer.
- codex 14y agoIf Linux kernel code looks like UNIX C code from 25 years ago, I'd argue it is C which hasn't aged well. C++'s true merit lies in its flexibility to evolve with the latest understanding of how to write good, abstract code with little runtime penalty, IMHO.
- rayiner 14y agoC++ never really lets you enjoy your abstractions because they're always so leaky. Low-level implementation details are always percolating to the surface. In practice I don't find C++ code any more readably abstract than similar C code. A really good example is libfirm versus llvm. The former is in C< the latter is in C++. They're both roughly the same order of magnitude in size (at least the core). They're both highly optimizing compilers. I find the former far more clear and readable. I personally find C++'s abstractions to be of questionable value. YMMV.
- SCdF 14y agoI think there is a real distinction between language features / design patterns / idioms that are enjoyable and efficient to write, and ones that enjoyable and efficient to read. And it's usually (for me at least) pretty hard to tell, except in hindsight. The general thought I try to keep with me, is that code is much harder to read than it is to write, and that if you need to be 'this' smart to write something, you need to be '>this^2' smart to read and comprehend it 6 months later. So you might think some code is a super clever trick now, that it solves your problem in a way you think is elegant and clever. In 6 months though, when someone else looks at it, they may come to a wildly different conclusion.