Skip to content

Instantly share code, notes, and snippets.

@alexpana
Last active September 17, 2024 06:47
Show Gist options
  • Save alexpana/91493a72b374651ab9ae to your computer and use it in GitHub Desktop.
Save alexpana/91493a72b374651ab9ae to your computer and use it in GitHub Desktop.
C++ is a hack

Various 'features' of C++ that show the hacky / inconsistent way in which the language was constructed. This is a work in progress, and currently contains some of the reasons I can remember why I've given up on C++. If you want to contribute, leave your favourite "hack" in the comments.

  1. (in)Visibility: C++ allows changing the access modifier of a virtual function in the derived class. Not only does C++ have no notion of interfaces, it actually allows subclasses to hide methods declared public in the superclass.

  2. Operator over-overloading: One of the increment operators takes a dummy int parameter in order to allow overloading. Can you tell which without googling? (hint: its postfix).

  3. Exception unspecifiers: C++ has two types of exception specifiers: throw() and nothrow. The first is deprecated (because 'we screwed up, sorry, let's forget about this terrible mess'). The second one guarantees it's contract by terminating the application when violated. That's because functions declared nothrow can still call legacy functions that don't declare anything (backwards compatibility and such), so the compiler can't validate your claim, choosing to explode in your face at runtime.

  4. Dependency hell: Without adding another layer of indirection via the PIMPL idiom, changes to the internal structure of the class propagate to all it's users, making compilation painfully / unecessary slow. Granted, the C++ object model requires this when the modified class is used as a value field inside another class, but C++ has no way of distinguishing between use cases. This is what you get for using a text preprocessor for handling dependencies.

  5. Binary incompatibility: Linkers are not standardised, so binary compatibility must exist between compilation units when linking. Not only are compilers incompatible, the same compiler used with different flags can generate incompatible obj files. Write once, compile everywhere.

  6. Multithreading: C++ did not have any standard multithreading implementation until C++ 11.

  7. RValue References: C++ has value semantics, which means it generates a copy constructor to deep copy value fields (convenient huh?). While the standard committe thought it was pretty cool, they eventually realised how many times objects were unecessary or accidentally copied behind the scenes (return values from functions, array operations, etc). So they invented 'move semantics', 'move constructors', and a new synthax for overloading on ephemeral 'rvalue references': &&.

  8. Name mangling: The C++ compilator was originally a preprocessor for C (CFront), and still maintains binary compatibility with C. C doesn't allow function overloading and doesn't have namespaces, so any function can be uniquely identified through its name (to avoid collisions, most libraries use a prefix when naming functions, such as gl*). Since C++ has function overloading, namespaces and classes, it allows multiple functions / methods to share the same name. The C++ compiler solves this problem by generating a unique identifier for each function. This is called name mangling, and uses the function's name, parameters, return type, namespace and class to create a unique name. The result is a horrible abomination that makes linker errors a pain to descipher. It's also non-standard, so every compiler has it's own name mangling scheme, making them incompatibile with each other. - https://isocpp.org/wiki/faq/mixing-c-and-cpp

  9. Inheritances: Since there are multiple access modifiers (public, protected, private), why not multiple inheritance(s)? There's even a virtual inheritance! While their meaning is beyond the scope of this rant, suffice it to say there are aspects that make them non trivial to understand / use. Scott Meyers wrote in his famous Effective C++ book: "protected inheritance is something whose meaning eludes me to this day". And he's a C++ guru.

@azm-gh
Copy link

azm-gh commented Feb 16, 2016

For beginners, it would be nice to give examples so it becomes also educational piece. Otherwise I see no reason why you should not keep your notes about C++ quirks public.

@FrankHB
Copy link

FrankHB commented Feb 17, 2016

  1. This is not a hack. Almost every language other than C++ does wrong. The visibility (of identifiers, not symbol visibility, the latter is related to linkage) is purely concerned with scoped names, that is, it has nothing to do with whether a name is denoting a function or not. So it has nothing to do with overriders. There is essentially no room to talk about virtual at all. This design allows the language specification split the name resolution rules in general (in C++ they are name lookup rules) away from the mess of inclusion polymorphism, which depends on particular subset of the type system (often badly designed for so-called OO languages). OTOH, languages like Java may probably have more obscure rules here. (What is the heck of "shadowing" vs. "hiding"?)
  2. Yes, this is an unintuitive hack. But if you don't want strangeness on not allowing overloading of postfix operators, you have no better choice. This is the sin of father (the C language). Think twice: why providing postfix ++?
  3. You've got it wrong. There is throw (ugly half-way copy of Java's throws) as well as noexcept (not "nothrow"). The reason of the "hack" is you cannot force every implementation perform inter-procedural optimization unconditionally without a standard of intermediate representation. (This is also one reason of why export is awkward.) Will you bother to put everything in headers?
  4. The hack is the standardization itself. It only specified (what is a) standard-layout class without any portable way to extend it.
  5. This is not related to C++, but almost all "native languages". There is even no single ABI standard covering all major platforms for one architecture. For C++, one notably de facto standard is the Itanium C++ ABI used by G++ and Clang++ broadly, but it is not compatible with "standard" MS toolchains on Windows.
  6. This is inaccurate. The correct one is: C++ has no threading model until C++11. (Nevertheless, so does C, until C11, which copies a lot from C++11.) You can still use pthread or some other platform-specific APIs for your C++98/03 programs.
  7. This is not a hack. A hack is to emulate the feature in C++98/03, as AA did in his "mojo". However, using of some special rules depending on it is a hack. The xvalue is a hack. Standalone (not migrated into the type system) value category (with some insane rules of reference types) is a hack. This is essentially the sin of forefathers again. In C, standalone lvalueness is a hack. In the B language, lvalueness as a grammatical feature is a hack.
  8. This is again not related to the language itself. C++ does not requires it. However, almost all practical implementations do in this way. Languages without standalone standardization process will be worse, e.g. Rust. It is not significant for these languages because they are lack of multiple competitive implementations. This is not the guaranteed future.
  9. Providing inheritance but not the general way to specify partial ordering among types is a hack. However, providing MI itself is not. On the contrary, lack of MI lead to ugly hacks when implementing mixins. Virtual base is not hard to understand and to use, you just have too many risks to use it wrongly, and it may cause ABI or performance issues which need you to use other hacks.

@hansderhase
Copy link

C++ is not the perfect language. It's designed to certain goals and practical considerations. Just like any other language. If the desgin goals don't fit your needs chose another language. You can't have it all in one language. That's a fundamental principle of language design. It's that simple.

Most if not all the "hacks" you list are rooted in the design goals of C++.

Glance over http://www.stroustrup.com/hopl2.pdf if you want to learn about how/why C++ came to be.

BTW: C++ perfoms pretty good in the language arena for a "hack", don't you think? Maybe there's more to the practical relevance of a language.

@agauniyal
Copy link

I would respectfully ask you to compare latest versions of c++ language to your choice of language for fair comparision. Otherwise it seems you're desperately trying to convince others to pick a language of your choice.

@Findecanor
Copy link

I would not say that C++ is a hack, but I would say that the raw language together with the standard library encourages a style of programming that indeed does consists of "clever hacks". Only that many of those hacks are not called "hacks" in the C++ community - they are called "idioms".
Programming should not be about clever hacks. Having to decipher existing code written by programmers who thought they were clever gets in the way of getting stuff done.

@FrankHB
Copy link

FrankHB commented Aug 30, 2017

@Findecanor Idioms have nothing to do with hacks. Hacks can live in any layer of a detailed design, while idioms are quite limited. A featured use of the language is an idiom when a) it identify a typical solution of some well-known problems, and b) the common implementation techniques required are not "dense" enough to be a pattern. Idioms are intended, by design. There are so-called anti-patterns, but almost no "anti-idioms".

As op shows, it is doubtful that average programmers (who only have experience on programming, but not designing of the language) have sufficient judgement of hacks in a language. Many features (e.g. pointers in C++) are essentially hacks in a general-purposed language, but users often ignore such facts. To complain against probably existed "hacks" in their minds does not get the stuff done at all. Having to decipher existing code written often clearly shows there is something wrong, but still not enough to attribute it to the language.

@alexpana
Copy link
Author

I would respectfully ask you to compare latest versions of c++ language to your choice of language for fair comparision.

Unfortunately, however shiny the latest version is, there are still lots of legacy codebases using old versions. Not to mention any C++ version is still compilable with the latest compiler. People still write C++ like it's 1990 today. There's just more ways to do the same thing or worse, to apparently do the same thing, but instead do something else. See https://herbsutter.com/2013/05/06/gotw-1-variable-initialization-or-is-it-310/

Otherwise it seems you're desperately trying to convince others to pick a language of your choice.

I really don't care what languages people are using, I'm not advocating for any other language. I'm just making a list of all the quirks I dislike about C++

@rsn8887
Copy link

rsn8887 commented Apr 13, 2018

This is a great list showing how hacky, crufty, inconsistent and kludged together c++ really is. And it makes it easy to just direct people here instead of explaining it every time. Thanks!

@fgeeyhd
Copy link

fgeeyhd commented Jul 25, 2022

ed

@fgeeyhd
Copy link

fgeeyhd commented Jul 25, 2022

``356436

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment