Skip to content
DevMeme
3595 of 7590
Languages Post #3932 · source on Telegram

C++ vs. Go: Choose Your Programming Reality

Description

A meme parodying 'The Matrix' red pill/blue pill scene. The character Morpheus has his face replaced with that of Bjarne Stroustrup, the creator of C++. He is depicted against a black background, wearing a black leather jacket and sunglasses, holding out both hands. In his right hand, he offers the red C++ logo, representing the 'red pill.' In his left hand, he holds the light blue Go language mascot, the Gopher, representing the 'blue pill.' The text at the top reads, 'You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe.' The text at the bottom reads, 'You take the red pill, you stay in wonderland, and I show you how deep the rabbit hole goes.' This meme humorously contrasts the philosophies of two major programming languages. C++ (the red pill) symbolizes the difficult but powerful path of low-level systems programming, with manual memory management and endless complexity - the 'rabbit hole.' Go (the blue pill) represents a simpler, more managed path with features like garbage collection and straightforward concurrency, allowing developers to remain productive without delving into the machine's deepest complexities. The joke resonates with senior developers who understand the trade-offs between ultimate control and high cognitive load (C++) versus simplicity and safety (Go)

Comments

24
Anonymous ★ Top Pick The blue pill is garbage collected so you can believe whatever you want about memory. The red pill is a raw pointer to 'wonderland,' which, if you're not careful, turns out to be a segmentation fault
  1. Anonymous ★ Top Pick

    The blue pill is garbage collected so you can believe whatever you want about memory. The red pill is a raw pointer to 'wonderland,' which, if you're not careful, turns out to be a segmentation fault

  2. Anonymous

    Blue pill (Go): accept 10 ms GC pauses and believe everything’s CPU-bound; red pill (C++): template-metaprogram your own allocator to save a cache miss - either way you’ll still serialize it all to JSON over HTTP

  3. Anonymous

    After 15 years of C++ template metaprogramming, you realize the real rabbit hole was the undefined behavior we segfaulted along the way - meanwhile, the Go developers already shipped v2.0 while you were still debugging that perfect move constructor

  4. Anonymous

    Ah yes, the eternal choice: take the C++ pill and spend the next decade debugging segfaults while manually managing memory like it's 1985, or take the Go pill and let the garbage collector handle your mess while you argue about whether error handling without exceptions is 'elegant' or just Stockholm syndrome. Either way, you're going down a rabbit hole - one just has more undefined behavior and the other has more opinionated formatting tools that will rewrite your code whether you like it or not

  5. Anonymous

    Choose Go and your GC hits the SLA; choose C++ and discover the rabbit hole is a stack trace through SFINAE, allocators, and an ABI mismatch that only reproduces under -O3

  6. Anonymous

    C++ blue pill: believe mutexes conquer all races. Go red pill: channels reveal how shallow that illusion runs

  7. @chekoopa 4y

    *getting dirty with C++ FFI in Haskell* oh 'tis hole sure is deep, mateys

  8. @erizpl 4y

    How about rusted pill? :D

    1. @feedable 4y

      don't

  9. @Dark_Embrace 4y

    1st coder: "pointers must be put to the right." 2st coder: "pointers must be put to the left." 3st coder: "pointers must be put in the center." Graphviz:

    1. @Dexconv 4y

      2nd, 3rd

      1. @Dark_Embrace 4y

        In C++ the 2nd (left) as it is part of type information. In C the 1st (right) to show a type of dereferenced variable.

        1. @sylfn 4y

          in C++ the second... int* a, b; What type does b have?

          1. @Dark_Embrace 4y

            I know. This is why it is recommended to use "one line - one new variable" rule.

          2. @sylfn 4y

            you can do using pi = int*; pi a, b; then both a and b will be int*

            1. @Dark_Embrace 4y

              Oh. Cool. Have not known this. The more you live 😅

            2. @sylfn 4y

              using a = b is C++11 style, old one (welcome to C and C++98) is typedef int *pi; or something (reading typedefs is such a pain)

              1. @Dark_Embrace 4y

                Yeah. It is pain.

              2. Deleted Account 4y

                Yeah "using" is more comfortable

                1. @SamsonovAnton 4y

                  Is this some form of sarcasm? How using New = Old; can be any better or worse than typedef Old New; when they are basically the same?

                  1. Deleted Account 4y

                    I didn't say they are different...

                    1. @SamsonovAnton 4y

                      Comparative form "more comfortable" assumes there *is* a difference between the two syntaxes.

                      1. @Dark_Embrace 4y

                        There is. Old tend to be of different length. While New is comparably the same. It is easier to search for New names. typedef typename iterator_traits<_InputIterator>::value_type _ValueType1; using _ValueType1 = typename iterator_traits<_InputIterator>::value_type;

          3. @Dark_Embrace 4y

            I think this can be more explanatory. In C++ there is a pointer-interconvertible term. It means that even if you reinterpret_cast from type A to type B you still has value "pointer to A". But the code will be written like you "have" B* var;. So the semantics of "dereferencing this variable results in type B" is wrong. And writing in C++ B *var; is misleading. In reality it is type A and UB. alignas(Y) std::byte s[sizeof(Y)]; Y* q = new(&s) Y{2}; const int f = reinterpret_cast<Y*>(&s)->z; // UB https://en.cppreference.com/w/cpp/language/static_cast#pointer-interconvertible I'm not familier with C, but I don't see this in specs. https://en.cppreference.com/w/c/language/cast In C++ there is also launder function that makes the life easier. Or not. I don't know for sure. That's all seems like Unsafe in Rust. const int g = q->z; // OK const int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OK https://en.cppreference.com/w/cpp/utility/launder And here is a stackoverflow with a better explanation on laundary. TL;DR compiler can optimise const member variable to be always the value you assign at runtime. And if you allocate a new object in place of old of different type (e.g. allocate type A from buffer of byte), you can not use the same pointer without laundary. https://stackoverflow.com/questions/39382501/what-is-the-purpose-of-stdlaunder And it is a somehow a basic concept, btw. :) https://timsong-cpp.github.io/cppwp/n4659/basic.life#8

Use J and K for navigation