| |
| ▲ | jstimpfle 11 hours ago | parent [-] | | Chasing an object model may work for simple programs, but as the program gets more complex, it tends toward an exercise in futility. The problem with the object concept is that there are many ways to partition all the data in a program into distinct objects. But types and object models need you to decide on one way of looking at the world, and it wants you to see the world like that throughout the codebase. Taking copying as a specific example, there may well be more than one useful way of copying stuff. The best way to achieve what you need depends not only on functional factors but also non-functional factors (such as performance and concurrency for example). The more serious and involved a program gets, the more apparent it becomes that there is not one way to copy. And the harder and more arbitrary it becomes to single out one way of copying that should be "blessed" with a special syntax. It's an arbitrary choice to single out a blessed way to copy, and that is also a choice against a lot of other useful ways to copy stuff. Having one blessed way makes a few things easier, but makes everything more complicated. There is now one way to copy that gets done quite implicitly using syntax, which draws on a mountain of special C++ semantics, and there are other ways that must be done using regular function calls. The end result is something that is more complex than just always making regular freestanding functions that do the thing that you want done. (What copy routine will be chosen implicitly by syntax/semantics is mostly predicated on types, so you can always opt to add wrapper types to accomodate other ways of doing things. Now try wrapping the members inside the thing that you want copied, working against all the implicit semantics... that must be about the point where the boilerplate becomes unbearable, where C++ gets much more verbose and unreadable than just straightforward C). The downside of always using function calls is that you can't profit from all the built-in implicit semantics stuff, but as said there is always a theshold of program complexity beyond which that stops being useful because there's much more stuff that the program needs to do that cannot profit from it. | | |
| ▲ | HarHarVeryFunny 11 hours ago | parent | next [-] | | I honestly don't understand the problem. A C++ object is copied using it's copy constructor, simple as that. If you are using STL container types, then there are no surprises - a copy means a deep copy. If you are writing a custom type with a custom copy constructor then of course you can implement whatever copy semantics you want to, but that is a strength of the language not a weakness. You can implement new types whose behavior is fully controlled by yourself. | | |
| ▲ | jstimpfle 11 hours ago | parent [-] | | > You can implement new types whose behavior is fully controlled by yourself. Exactly, that's what I do. Now notice that there is not a good incremental way to go from this object model stuff, to a toolbox that lets you build many more routines out of reusable primitives (implemented mostly as POD structs and freestanding functions). It becomes worse if one has also made a lot of use of these silly access protectors, public/protected/private. Which means that, when you start out with the C++ object model, and evolve the codebase, you are invariably going to paint yourself into a corner, and proceeding requires first undoing all the fluffy object stuff. That's not some furious ranting disconnected from reality on my end. I've seen it many times in practice. Show me any large complex serious systems codebase that makes extensive use of that silly implicit stuff, where all the important function calls are basically out of your control, hidden in the "whitespace"... no, that's not the way to write a complex program. It doesn't work. For balance, I concede that even large programs can use some self-contained container types, like std::vector, or even custom built ones. That's where the object model still works -- small, isolated stuff. However, as you scale, you tend to not include many isolated types. You program probably needs a good grip of memory allocation for example. | | |
| ▲ | HarHarVeryFunny 10 hours ago | parent [-] | | Some of the worst code (codebases) you will see is C++ code written by people who are new to the language and think that it is the right thing to do, or just cool, to use every feature of the language. C++ is a massive language, that has really grown too big, and is fraying at the edges. This is probably the fate of any old language - it either keeps growing adding more modern features, or it stops growing and becomes obsolete. It's hard to always add new features while retaining backwards compatibility, but backwards compatibility is what users demand, so the result is languages like C++ that are screaming for the feature set to be refactored and simplified... Using C++ well is requires knowing when it's appropriate, or not appropriate, to use the features it provides! |
|
| |
| ▲ | HarHarVeryFunny 11 hours ago | parent | prev [-] | | One more thought ... I think it's a mistake to associate C++ classes with object-orientated design or some program-wide high level design choice. A better way to think of them is just as custom types, and as a convenient packaging of data and and the functions (class methods) that works on the type/data. In fact using OO concepts such as inheritance, and god forbid multiple inheritence, in C++ is generally a bad idea unless you have a very specific reason for doing so. You shouldn't have the mindset of "I'm using C++, so my classes should be using inheritance". In general keep your class hierarchies as flat as possible, and most of the time you don't want inheritance at all - you are just creating a packaging of data + associated methods. Of course there is also nothing stopping you from combining classes with methods with additional global functions that work with those classes, but it would be advisable if they only did so using methods provided by the class, rather than having class data members declared public and letting things outside the class modify them. The point* of classes - packaging data and the methods that work on the data together - is to support easy and localized future changes. If your class data members are private and only operated on by class methods, then you can change the data members however you like and users of the class will not be affected. Used properly, C++ classes are an enabler for writing large complex projects that are easy to maintain. If using classes is impacting the design of your project, then it really means you are using them in the wrong way. Edit: * Well, one point. The other main point/value is the support of constructors and destructors so that your classes/structs are guaranteed to be initialized and destroyed. You don't need to remember to call an initialization function, or need to worry about code that throws exceptions and therefore has many paths where structure cleanup/destruction would be needed - the destructor will always be called when the object goes out of scope. |
|
|