Hacker News new | ask | show | jobs
by userbinator 793 days ago
IMHO this is another case where C++'s hidden layers of complexity hides bugs that would've been obvious in plain C. In fact for this particular use-case I'd probably use indices instead of pointers.
3 comments

I remember the C++ ca. 1994 year when I started my career. It was C with Objects back then. And it was great! C++ was better C, it was easy for any C dev to convince him/her to jump to it.

I recently had to work with C++ code and... it is not a happy story anymore:

- Lots of magic like described here

- F**ing templates - for those who like them, did you ever see a C++ core file? Or tried to understand a single symbol?

- Standarization that feels like pulling more Boost into the language, which means more templates. Which makes core files incomprehensible.

It used the be that average dev who knew C could read and work with simple C++. This is no longer true. C++ is no longer a better C.

P.S. Example from recent core file, one line in the stack trace: boost::asio::asio_handler_invoke<boost::asio::detail::binder2<core::AsyncSignalCatcher<2, 15, 17>::waitForSignal<XServer::m_accept_loop(tsr::Data&)::<lambda(spawn::yield_context)>::<lambda(int)> >(XServer::m_accept_loop(tsr::Data&)::<lambda(spawn::yield_context)>::<lambda(int)>&&)::<lambda(const boost::system::error_code&, int)>, boost::system::error_code, int> > (function=...)

> I remember the C++ ca. 1994 year when I started my career. It was C with Objects back then

It is possible, and perhaps even likely that the C++ you wrote in 1994 was indeed this "better C" and maybe even the C++ you read, the language Stroustrup wrote about in 1985 although "C with Objects" is much older still. The ISO document (C++ 98 aka ISO 14882:1998) was four years into your future in 1994, but the committee to write that document had existed for quite some time. Stroustrup's 1991 Second Edition of his appropriately already big book "The C++ Programming Language" explains that the committee have accepted Templates, although I believe at that point they didn't realise they'd inadvertently thus added an entirely new meta-language which is programmed differently than the rest of C++

Boost comes much later, it's only about as old as the actual ISO document.

I believe that not many developers really wanted C++ and craved Object Pascal instead.

I don't like Pascal but I have to admit that Object Pascal is a succint and successful addition of OO to a manually memalloc language, whereas C++ is neither.

As someone that went from Turbo Pascal to C++, while enjoying Borland's ecosystem, the reasoning was clear.

A programming language that at a time offered similar security and features, with much better portability.

Never was a big C fan, with Object Pascal and C++ on my toolbox.

Turbo C++ for Windows 3.1, released in 1993, already had support for templates in its initial design form.

Borland C++ 2.0, or 3.0, rewrote BIDS from preprocessor magic into templates.

CSet++ for OS/2, also early 1990s also offered template based collections.

By 1996, MFC introduced template based collection classes as well.

I started with Stroustrup's C++, it already had templates back then.
Templates as in C++ are a historical accident.

Erwin Unruh demonstrated to the C++ commitee how they had accidentally created a second, compile time programming language inside the primary language. He did this by calculating primes and printing them in error messages.

People got carried away a bit with the power made available by this new language. Unfortunately there are no basic ergonomics in template metaprogramming because it was not intended to be a programming language.

boost is just awful. Don’t use boost.

templates are totally fine for basic containers. Much better than C macro shenanigans.

The world is still looking for a “better C”. Zig, Odin, Jai and probably more are all trying. Of the three I think Jai is the closest. But it’ll be awhile.

> - F*ing templates - for those who like them, did you ever see a C++ core file? Or tried to understand a single symbol?

I have 20+ years of experience writing C++.

Yes, I've looked at "core" C++ headers and source. The most annoying part to me is style (mixed tabs and spaces, curly braces at wrong places, parenthesis or not, the usual style complaints). But other than that they're very readable to a seasoned C++ engineer.

I've also tried to understand symbols. You're right, they're difficult. But there's also tooling available to do it automatically. Even if you don't want to use the tools, there is a method to the madness and it's documented...

Let me ask ChatGPT:

> What tool lets me translate an exported symbol name to a C++ name?

    C++filt
It's categorized as a demangler. That's your search term to look for (I had to remember what it was).

Then I asked:

> Is there a function in the standard library which allows to mangle or demangle a given name or symbol?

It tells about `__cxa_demangle` for GCC. While I had forgotten about that, I'm pretty sure there is (or perhaps something similar) in the standard library.

It also suggests to use a library such as `abi::__cxa_demangle`. Hah, that's what I was looking for. It's an implementation-specific API (eg, compiler-specific) API used as an example. It was mentioned on `std::type_info::name()` page here:

https://en.cppreference.com/w/cpp/types/type_info/name

So, to continue replying to you: yes, it's annoying but it's solvable with tools that you can absolutely integrate into your IDE or command-line workflow.

> - Standarization that feels like pulling more Boost into the language, which means more templates.

The boost libraries are open source and their mailing lists are active. If you don't like a given library because it has too many templates then you could make one with fewer templates.

And, as standardization goes, it's also quite open source. The C++ committee is very open and receptive to improvements. The committee are volunteers (so their time is limited) and (usually) have their own improvements to the standard that they want. So you have to drive the changes you want (eg, actively seek feedback and engagement).

> P.S. Example from recent core file, one line in the stack trace:

I've seen much longer -- I've seen templates entirely fill a terminal buffer for a single line. That's extremely rare, definitely not fun, and debuggability is absolutely a valid reason to refactor the application design (or contribute library changes).

I find it useful to copy the template vomit into a temporary file and then run a formatter (eg clang-format), or search/replace `s/(<\({[)/\1\n/g` and manually indent. Then the compiled type is easier to read.

Some debuggers also understand type aliases. They'll replace the aliased type with the name you actually used, and then separately emit a message (eg, on another line) indicating the type alias definition (eg, so you can see it if you don't have a copy of the source)

>> - Fing templates - for those who like them, did you ever see a C++ core file? Or tried to understand a single symbol?*

> I have 20+ years of experience writing C++.

> Yes, I've looked at "core" C++ headers and source.

https://en.wikipedia.org/wiki/Core_dump

Ahh, core dump, not "core" file. Ok, slightly ambiguous and I feel sheepish about it.

I've also looked at core files in GDB, not directly. They're about as unintelligible as a core dump from a C program. It all depends on -fno-omit-frame-pointer: with it, it's usable. Without it, good luck because it involves un-convoluting the optimizer. That's both for C and C++.

In far more cases, zero-cost abstractions make obvious or impossible bugs that would be hard to spot in C programs, e.g. memory lifetime rule violations. And you could make a similar argument that C obscures bugs that would be obvious in assembly. High level languages are a blessing, and programmers who avoid them are only decreasing their productivity and those around them.

The problem the article highlights appears to be an implementation defect: in my libstdc++ test just now, we do, in fact, mark the list as nothrow move constructible. The standard should mandate that std::list be infallibly moveable.

Are we going to indict a whole programming model based on an isolated implementation bug? If so, well, isn't doing that from a "C is better" perspective the galactic black hole calling the kettle black?

    #include <cstdio>
    #include <list>
    #include <type_traits>
    #include <vector>

    struct Node;

    struct Connection {
        Node *from, *to;
    };

    struct Node {
        std::vector<Connection> connections;
    };

    int
    main()
    {
        printf("%d\n", std::is_nothrow_move_constructible_v<std::list<Node>>);
        return 0;
    }
I mentioned it in a side note that I trimmed because there were so many that it spilled into the footer (faster to trim the article than to fix the CSS,) but Microsoft is the only implementation of the big three that doesn't mark the move constructor here as nothrow. The standard doesn't require it so it's valid for MSVC to do things the way they do, it just creates problems like this that would arguably be harder to find the cause of if one had to build code for multiple platforms.
Right. My point is that 1) this is a quality-of-implementation issue in MSVC, 2) the standard should be phrased such that the MSVC implementation is illegal, and 3) the C++ standard library solves a lot more problems than it creates despite having warts like this and C++ having some unfortunate defaults (e.g. mutability by default).
On the flip side C projects often end up with things like linked lists and pointers to [it depends] because that lack of abstraction, while obvious, encourages the programmer to take shortcuts (otherwise no time for actual logic)