Hacker News new | past | comments | ask | show | jobs | submit login

I agree that C++ is bad but I actually find C much worse for projects bigger than a few thousands of lines. Reasons for this:

* lack of namespaces - all names with long prefix look the same to me

* just text based macros

* no generics

* error handling usually based on int constants and output function parameters - in big projects is hard to use them consistently without any type checking

* no polymorphism

* ton of undefined behavior (almost the same as C++)




All your complaints about C are valid, except I'd say defined but stupid behavior buried somewhere in a gargantuan language spec is effectively the same as undefined behavior.

The difference is, C lets you control how much baggage you carry along and C++ doesn't. If I want a higher-level abstraction in C, I can usually implement it pretty well using inlines and macros, void and function pointers. Will it be pretty? Hell no. Will it have all of the syntactic sugar that the C++ version does? Nope. But it will work and be usable and most importantly the complexity/risk that it carries along will be exactly what I asked for (because I know how to manage it). Using a feature in C++ means carrying along all of the baggage from its dependencies and interactions with every other feature.

If programming languages were cars, it's like the dealer saying I can't add one option to the base model. No, I have to buy the top-of-the-line model with dozens of features I don't actually care about and will never use, costing far more and oh by the way that model has door handles that will cut you. That's about when I go to the Python dealership down the street, or just stick with good old C.


> Using a feature in C++ means carrying along all of the baggage from its dependencies and interactions with every other feature.

Only if you use every other feature. Don't do that. Use the features you need (and understand well), not every feature. It actually becomes much like you say C is, except that you don't have to write the features.


> Only if you use every other feature.

Not true at all. A lot of the features have either an interface or an implementation driven by the possibility of combination with some other feature. The cognitive and/or performance costs remain even if that other feature isn't used. For example, it's easy to get mired in writing extra constructors/destructors and virtual hooha just because someone using your class might also use some feature besides the one you used yourself. I've seen that happen on many projects. The only way to avoid it seems to be to abandon most of what makes C++ different than C, at which point it would usually make more sense to start with C and add what you need.


> For example, it's easy to get mired in writing extra constructors/destructors and virtual hooha just because someone using your class might also use some feature besides the one you used yourself.

I don't think I've ever seen that. (In a library, sure. In application code, no.) If you know it's going to be needed (or you know it's very likely), sure. If not, every place I've worked in added the extra constructors when needed, and only when needed.

Extra destructors? Other than empty destructors, I don't think it's possible to create an "extra" destructor, because each class can only have one. (And, in the case of virtual destructors, adding them is good practice. But that's not "combination of features", it's part of the deal you sign up for when you start using polymorphism. (Though I guess you could describe it as the combination of destructors and polymorphism, which is true, but it's simple enough I have a hard time regarding it as out-of-control complexity explosion.))


> In a library, sure. In application code, no.

It has been a long time since I worked on an application so trivial that parts of it weren't broken out into separate libraries. Most often, those libraries end up being maintained by people other than their users, and the users always end up using the library in unexpected ways or contexts so these protective measures always become necessary.

Perhaps more to the point, I don't think there should even be multiple constructors each called in different situations that it takes several pages to describe. This complexity mostly exists because the people who defined C++ don't seem to understand the significance of value vs. reference semantics, as the OP also noted. Move semantics and rvalue references represent a tacit omission that the previous semantics were broken, but they just introduce even more non-intuitive syntax and another few pages to describe what happens in which situations. That's exactly the kind of spurious complexity that makes compiler writers want to go on killing sprees and folks like me want to avoid the whole morass.


Never really had a problems with the lack of namespaces actually (and not due to insanely prefixed names), if everything is properly seperated there just doesn't seem to be enough chances for name clashes: headers should have only things which really are publicly needed, sources should only include headers they need, and one of the design targets should be high cohesion/low coupling. Though it probably depends on the project.


> no polymorphism

C has plenty of polymorphism. The compiler just doesn't do it for you. In fact, C++ started out as C-with-classes since it was a pain to keep recreating the OOP-in-C boilerplate over and over. Besides, there are more kinds of polymorphism than virtual methods. You can be polymorphic with an array of function pointers.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: