HN Theater @HNTheaterMonth

The best talks and videos of Hacker News.

Hacker News Comments on
Modern C and What We Can Learn From It - Luca Sas [ ACCU 2021 ]

ACCU Conference · Youtube · 144 HN points · 2 HN comments
HN Theater has aggregated all Hacker News stories and comments that mention ACCU Conference's video "Modern C and What We Can Learn From It - Luca Sas [ ACCU 2021 ]".
Youtube Summary
#Programming #Cpp #AccuConf
Slides: https://accu.org/conf-previous/2021/schedule/
ACCU Website: https://www.accu.org
ACCU Conference Website: https://conference.accu.org
ACCU Twitter: @ACCUConf
Streamed & Edited By Digital Medium Ltd: https://events.digital-medium.co.uk

------
C is often perceived as an antiquated language that is mostly used for legacy purposes, but many people still prefer coding in C or in a subset of C++ that is very close to C. This is sometimes labeled "Modern C" and the ideas behind it are becoming more popular alongside other paradigms such as Data Oriented Design (DOD), Zero Is Initialization (ZII) and Centralized Memory Management (CMM). In fact, many new systems programming languages, such as Rust, Go and Zig, also embody a lot of similar ideas as Modern C showcasing a high degree of interest in these paradigms. In this talk we will explore how programming looks like with this different approach to C and how it addresses matters such as API design, error handling and resource management as well as what are the benefits and costs of these techniques. By the end we will gain a better understanding of how these ideas can help improve the quality of our code, what new languages have adopted similar concepts and to what extent, and what lessons we can learn from this in order to improve our own existing codebases and styles of coding.

------
Luca Sas
Luca Sas is a Core Systems Engineer at Creative Assembly who has been coding for almost a decade and is passionate about system architecture and low level programming. Some of his previous work includes mobile apps with some of the biggest NGOs in Romania and video game development. In Romania he was a national champion at programming contests and olympiads where he is now a judge. He enjoys attending conferences and talking to developers about their experience and learning about ways to improve software design as well as mentoring new programmers and giving talks. Previously he gave talks at programming events in Romania and the University of Leeds, and ACCU 2019.

------

Future Conferences:
ACCU 2022 Spring Conference, Bristol (UK), Marriott City Centre:
2022-04-05 to 2022-04-09.
-------------------------
HN Theater Rankings

Hacker News Stories and Comments

All the comments and stories posted to Hacker News that reference this video.
"Modern C and What We Can Learn From It - Luca Sas [ ACCU 2021 ]" - https://youtu.be/QpAhX-gsHMs

"Linux User/Kernel ABI: the realities of how C and C++ programs really talk to the OS - Greg Law" - https://youtu.be/4CdmGxc5BpU

Yes, that’s a very clean and robust approach. In the “Deferred resource release → Related work” section, one of the links is to a video from the ACCU 2021 conference by Luca Sas titled “Modern C and What We Can Learn From It” that explains modern C techniques, and your one is mentioned at 23′15″: https://youtu.be/QpAhX-gsHMs?t=23m15s

If you haven’t watched it, I can recommend it.

May 06, 2021 · 140 points, 129 comments · submitted by pmarin
throwaway20014
Anyone who wants a very good modern C book that's only 272 pages, take a look at 'Effective C - An Introduction to Professional C Programming by Robert C. Seacord. [1]. It's from 2020.

Robert Seacord is a Technical Director at NCC Group where he develops and delivers secure coding training in C, C++, and other languages. Seacord is an expert on the C Standards committee. > That's some solid credentials. He focuses on secure C code in the book.

Here's a short article on why he wrote the book [2].

[1] https://nostarch.com/Effective_C

[2] https://ieeexplore.ieee.org/document/9237323

IgorPartola
Hi Robert! :)
throwaway20014
? . I'm not Robert. Just wanted to mention his book.
nathcd
Per the HN guidelines:

> Please don't post insinuations about astroturfing, shilling, brigading, foreign agents and the like. It degrades discussion and is usually mistaken. If you're worried about abuse, email [email protected] and we'll look at the data.

https://news.ycombinator.com/newsguidelines.html

cptnapalm
I believe it's important to always mention in conjunction with this book that, after decades of existence, the No Starch finally discovered C's natural mascot: Cthulhu. Cthulhu is powerful, to be respected and feared and, if malignantly unleashed, will be the end of the world. Just like C.
Arnavion
The presenter has discovered the Result / Either monad at 00:24:16, but their proposed C implementation sounds like a really bad idea:

- The flag needs to be manually inlined into every type, thus bloating the type even after the value has been successfully created. ie every instance of `file_contents_t` in your program has become the equivalent of `Result<file_contents_t>` and you have to check it for validity every time you use it, not just when you create it.

- The flag is easy to forget to check. `std::optional` has that problem too with its `*` and `->` operators, but at least you have to write them, as well as the type "std::optional", explicitly. You can't accidentally use a `std::optional<file_contents_t>` as a `file_contents_t`, but you can accidentally use a `file_contents_t` with `.valid = false` where one with `.valid = true` was expected.

- The `img = crop_to_cat(img); img = add_bow_tie(img); ...` example looks great when you just call the functions in sequence and expect each function to be a no-op for invalid inputs. But this breaks down when you have loops or logging or sleeps or other side effects that you genuinely want to skip. At that point you will have to start checking `if (img.valid)` manually again anyway. And if there are enough of these scattered around multiple scopes, you'll end up wanting `goto error` again.

The callback-based example with `std::optional` as well as the Rust example with early returns don't have these problems. (Incidentally the Rust version uses an explicit `match` and manual return of the error for some reason, even though that particular usage pattern is exactly what the `?` operator is for.)

DougBTX
> thus bloating the type

Mildly off-topic, but as of Rust 1.50 [0], Option<File> is now the same size as File, as "-1" can be used to represent no-file. You're completely right though about how it would be good to unwrap it as soon as possible once it is successfully created...

[0] https://blog.rust-lang.org/2021/02/11/Rust-1.50.0.html#a-nic...

enqk
Having used the “local errno” solution, I feel you’re overstating the downsides a great deal.
dthul
I agree. `crop_to_cat(img)` now has to be concerned with handling a possibly invalid image even though this method doesn't make sense for an invalid image. It muddies the type signature of the method and instead of `Image -> Image` (or possibly `Image -> Either Image Error`) it has to read `Either Image Error -> Either Image Error`.

What if I want to apply that method to a valid image? I either need to wrap the image or provide different overloads of the method which can get quite tedious if the number of possibly "fallible" parameters grows. A macro for unwrapping and early return would be nicer.

amadvance
Not to mention that you also lose the error context. That boolean "is_valid" flag is not really informative of what happened.

For example, if the image to load doesn't exist, you may want to print/log such path.

The goto looks like a better approach.

flohofwoe
You can just as well use a nested common error struct which has more detailed error information instead of just an "is_valid" bool, and also turn the whole return value into a tagged union to save some space (so the return value either contains a success value, or error data, but not both).

You just don't have the high-level syntax sugar to create or deal with tagged unions in C.

jhauris
As a professional C++ programmer who hasn't used C since the compiler limited me to C89 (so 2015ish), I am very impressed by how clean C code can look these days. This was a great talk. There are a lot of really good things in modern C, and if I ever have to use C again I will have some great new tools. And I found the "25k allocations for a single character entered" in chrome extremely shocking; it definitely pays to think about allocations in C++.

Given the improvements, I found the warning not to use libc unless absolutely necessary very surprising. I suppose C++ has parts we know to avoid, but I wonder why, with all the improvements to the C language, there haven't been the same improvements to the standard library? It appears C programmers are used to rewriting pretty basic functionality for every new project, or carting around their personal utility library.

I'm also still not at all convinced by macros.

synergy20
What I really want, is a C++ book that lists the absolutely must-have features for a beginner-intermediate programmer, I don't want to be overloaded(no pun intended) with all those 2000 advanced features, I can read an advanced level book when I'm ready.

Basic types, smart-pointers(how to use them and when to use them), basic OOD and template(but no advanced tricks), essential algorithms and containers, that's about them. No need on constexpr, rtii etc for now.

In this fast-paced world it's hard to get interested in any books more than 300 pages for me.

ku-man
I also wish such book could exist. Seems we have to rely in our instincts to realize when an author is getting a bit too "enthusiastic" with C++.
lfowles
"A Tour of C++" is only 256 pages and the 1st edition is what I used to get into modern C++ in the workplace years after a strange mix of C/C++ labs in college.
synergy20
true, a great book that I'm reading now, but it's more of a 'tour guide' indeed. It's probably the closest I can find however.
squarefoot
What book would you suggest for someone who started on the K&R 2nd Ed. then didn't write a line in C for about 15 years? I would appreciate something near the K&R style, but updated with the latest changes to the language, security related caveats etc.
zvr
Modern C, https://modernc.gforge.inria.fr/
squarefoot
Thanks, looks interesting. I would order the dead tree book if it wasn't from Manning, which uses a layout that is almost unreadable to me: thin fonts and no bold text where it should be. just take a look at the difference from the CC licensed .pdf and the livebook at Manning's site, and on paper it'll be even worse (been burned before with the otherwise excellent Nim book which is hardly readable as well).

Why is it still so hard to replicate the readability of the K&R after so many years? Please stop using thin fonts!

makapuf
It is to be noted that designated struct initializers will be/are in C++20 (of course it has all the features, it's C++). See it here: https://en.cppreference.com/w/cpp/language/aggregate_initial...
flohofwoe
Unfortunately the restrictions added in C++20 make designated initialization quite pointless for any structs or classes with more than a handful items. Having to remember the order of initialization is too much hassle in this case.
mfost
This completely ignores the advantages they have in code readability and reliability.

I can well deal with a little extra effort to order the initializations for those benefits.

Now, if you complained about the burden on refactoring member orders it poses on the other hand?

hmry
That's what I thought too, until I actually used them extensively. The compiler tells you the correct order when you get it wrong, and I'm sure if you used an IDE (I don't) it would help you as well. And that was with Vulkan, everything in that API is done by creating structs with way too many members.
flohofwoe
That sounds like a game of Tetris though, with or without IDE support ;) It would have been better if C++ treated structs like C structs, not like classes, but too late for that I guess.
david2ndaccount
The C++ version is much worse. "Note: out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++.”

Arrays designed to be indexed by an enum is a pattern I use all the time in C and designated initializers make it a whole lot safer and reduce the likelihood of a bug when refactoring.

varajelle
The out of order initialisation is not supported because it would be confusing with the order of destruction. Note that initializing the members in a constructor in a different order is allowed, but they are actually still initialized in the declaration order. That's quite confusing and most compiler warn about that. So in a way it's good the same mistake was not done in designated initialized.

I don't know why the array notation is not allowed in C++.

flohofwoe
Apparently the array initialization clashes with lambda syntax.

Regarding all the restrictions added in C++20:

Clang supported the full C99 designated intiialization feature set in C++ without any issues long before C++20, so the decision by the C++ Committee to add those restrictions is quite baffling, considering that there is a solid implementation in the wild that has been working just fine for many years.

an1sotropy
An account of modern C should also note <tgmath.h>, which came with C99, and makes "sin()" and "cos()" do the right thing w.r.t. argument type (float, double, long double), something that has long been possible in Fortran. In C, this allows you to typedef a "real" type, set to either float or double at compile-time, in order to conveniently explore trade-offs associated with the different floating point precisions. The implementation of tgmath.h is an incredible hack though https://www.pixelstech.net/article/1324906407-The-ugliest-C-...
cygx
Note that C11 added _Generic to the language, so things like the type-generic functions from tgmath.h can nowadays be implemented in user space.
an1sotropy
Indeed; thanks. I do appreciate knowing that <tgmath.h> does this for all the math functions in one fell swoop.

speaking of FP-precision genericity, I really wish there was a format specification for printf that would reliably print a floating-point number with just enough digits to recover the bits of the given value (float or double), but the given value will already have been promoted to double since printf is variadic.

belgesel
Although I disagree with some part of the presenter's ideas. I learned struct initializers and _Generic keyword from the presentation. So that is a great win for me. Now I can write safer code with the const and non-const pointer types.

Suppose that I want to return a pointer to a field inside of a struct. Either I had to write const and non-const versions of the same function and use them which brings unreadable code. Or I would have to define argument as const and return non-const pointer which defeats the purpose of const in the first place.

This keyword allows me to use same function name with const and non-const pointers.

an1sotropy
I just noticed your comment and I'm intrigued. Can you explain more or give a tiny example of this const/non-const flexibility?
belgesel
Suppose I have the following struct and functions.

  struct my_struct{int a; char private[10];}
  void * get_struct_field_nonconst(struct my_struct *ptr)
  { return &(ptr->private[0]); }
With these elements you are only allowed to give non-const pointers to read or write inside private field. In order to truly apply this to const pointers (no casting etc.) you will need another get_struct_field() function but defined as this.

  const void * get_struct_field_const(const struct my_struct *ptr)
  { return &(ptr->private[0]); }
This will work but it is ugly. Here _Generic keyword allows you to write these functions but use them with a common name. Such as get_struct_field(). And that would be something like this:

  #define get_struct_field(ptr) \
  _Generic((ptr), \
  const struct my_struct * : get_struct_field_const, \
   struct my_struct * : get_struct_field_nonconst) \
  (ptr)
Hope this would help!
an1sotropy
(slow answer) yes, thanks for the example!)
amelius
Is it possible to translate C into (unsafe) Rust while maintaining both human readability and link-level compatibility?
dnautics
this is an evolving, and first-class capability of zig (you can run it now, the issue isn't closed because it's an epic)

https://github.com/ziglang/zig/issues/2457

MrRadar
Have you considered D's "Better C" mode? https://dlang.org/spec/betterc.html
dmytrish
There is also https://github.com/jameysharp/corrode

I have not used it, but I doubt it's possible to translate C into idiomatic Rust mechanically.

pornel
I've attempted to implement this: https://lib.rs/citrus

And my conclusion is: No.

• Rust deliberately makes unsafe syntax ugly and noisy to steer users towards the good parts.

• C idioms are very different from Rust, and much harder to translate to "nice" Rust than it seems (e.g. getting rid of linked lists, or translating `goto cleanup` to RAII, pointer arithmetic to iterators quickly runs out of trivial cases and becomes a Sufficiently Smart Compiler problem).

There's https://c2rust.com that at least preserves semantics accurately.

0xdeadbeefbabe
What is isize_t?
belgesel
Presenter doesn't give any information about it. But I think it is not a type defined in C standard and presenter's own implementation.
harry8
Association of C and C++ Users (ACCU)

They should really just call themselves the ACU, they are wildly pro C++. It's progress that there is even a C talk at all at their conference but even looking at the title it's pitching itself at "No really, C isn't completely worthless"

One day such language wars might seem quaint. While everyone has their livelihoods tied to their chosen technologies it probably won't. C++ is fine imho fwiw. It's just not anything like "always and everywhere a better choice that C which should be treated as a virus."

The Scala folk are worst at it around here that I've seen but my experience may not be yours. People used to say similar of the LISP people on newsgroups. Perl was the first I saw where Larry and co. spent a lot of resource trying to make that not happen in the community. Python did a decent job following from what I've seen. C++ has always been pretty brutal in silly ways. I hope for it to calm down. Having one purely C talk at the conference of the Association of C and C++ users might be considered in some spheres to be "progress of a sort."

edit: disclosure. I am a member of the ACCU.

kaba0
Not trying to start a language war, but what exactly would you use C for? C++ is just as good at embedded, and you can use it as basically a slightly less foot-gunny C. And there is also Rust and Zig, if that’s not really what you want.

I just can’t really use C with that amount of namespace pollution, at least namespaces should be added. And purely text-based macros are the worst thing ever.

pjmlp
UNIX/POSIX clones.
david2ndaccount
Rust is very, very complicated and Zig is not stable.
derefr
I prefer C, but I technically write C++ because my “C code” sometimes uses references instead of pointers. (Why did that never become a C feature, anyway? It’s completely independent from OO/exceptions/templates/etc.) Luckily, in most any environment you can name, installing a C compiler actually implicitly installs a C++ compiler as well; so I can hand my “C code” library to people and tell them it’s C, and the fact that there’re a few .cpp files in there won’t be a problem, any more than having some .asm files in there would be.

I’d like to use std::string as well, but I want my code to externally obey the C FFI, rather than the C++ one (I.e. no need for the linking code to know it needs to initialize the C++ runtime), so I can’t really use any STL. Still wishing C had a standard, portable, found-in-all-compilers prefix-length strings library...

flohofwoe
> Why did that never become a C feature, anyway?

I would rather ask, why did C++ add another reference type next to pointers ;)

PS: the important part is that libraries have a C API, whether the implementation underneath is written in C or C++ isn't all that important. But IMHO once you're restricted to a C API anyway, writing the implementation in C too makes more sense because there's fewer situations where the implementation clashes with the interface.

pjmlp
Because that allows for out parameters and referring to memory addresses without the unsafety of dealing with pointers, something that even ALGOL and PL/I supported.
flohofwoe
> allows for out parameters

Out parameters are mostly a legacy feature from the time when C compilers didn't allow struct return values though, or implemented this inefficiently (besides, out parameters via pointers works too).

> memory addresses without the unsafety of dealing with pointers

I never understood the "increased safety" argument. C++ references can become dangling just as easily as pointers, and arguable they're even worse, because most of the time they look like regular value types.

jcelerier
> Out parameters are mostly a legacy feature from the time when C compilers didn't allow struct return values though, or implemented this inefficiently (besides, out parameters via pointers works too).

ah yes, that legacy, age-old GCC 11 compiler https://gcc.godbolt.org/z/rYsxxTxqd

syockit
Wow. The function produces identical code when inlined, so why does the C version require that memcpy when it's not inlined?
jcelerier
because C++ allows RVO and not C (as this is technically a change in behaviour as one may instrument memcpy - there are also a few cases where the copying of the return value of a function is observable so this does not fall under the default "as-if" rule of optimization)
flohofwoe
Clang produces identical code between C++ and C:

https://gcc.godbolt.org/z/vWqn4s5ev

I don't think that C disallows RVO, gcc just might be more conservative there (maybe because of special Linux requirements)?

jcelerier
> I don't think that C disallows RVO,

optimizations should never change the output of a program unless explicitely allowed (the as-if rule).

In c++ since RVO is allowed, it is ok for

    intptr_t value = 0;

    struct foo f() {
      struct foo the_foo;
      value = (intptr_t)&the_foo;
      return the_foo;
    }

    int main()
    {
      struct foo the_foo = f();
      assert(value == (intptr_t)&the_foo);
    }
to assert or not depending on the -O level. But I'd wager that it is not the case in C.
pjmlp
Out parameters are a welcomed feature of all memory safe systems programming languages, only missed from C and BCPL.

C++ references surely are safer than pointer that can point to whatever they feel like and aren't initialized to any safe value.

There is a difference between being 100% fully safe, which they aren't, and being safer than plain unsafe pointers Assembly style.

cygx
> C++ references surely are safer than pointer that can point to whatever they feel like and aren't initialized to any safe value.

From the C programmer's perspective, a reference is a constant pointer with automatic indirection.

As far as 'safety' is concerned, there's not much difference between

    int& ref = ...;
and

    int *const ptr = ...;
except in the most trivial of cases.

edit: However, this of course does not mean that references are useless within the C++ context - they do have an effect on how you write your code...

benibela
Easier to write . than ->
jstimpfle
but less clear.

Some of the newer languages do aways with -> completely but I think it just obscures the data structures.

The one frequent annoyance that I had with . vs -> is that for access local variables I need to use . and if I make that code into a function that takes the local variables as a pointer, I need to change the code into ->. In other words, I can't easily move the code through stages of solidification using simple copy & paste.

That's why I tend to declare my local variables using pointer literal syntax, e.g.

    Foo *local_thing = &(Foo) { ... };
That way it gets easier to move the code out.
jstimpfle
Although I've never found it useful, I believe if you do

    TYPE *const ptr = foo();
to initialize a C pointer where you can't change what thing it points to (as opposed to the thing itself), then you get 100% of the alleged safety benefits that you get from C++ references.

Except, you're not adding another type category in the type system, with all the complexities (non-orthogonality of features) that come with that.

Granted, compared to C++ reference declarations like

    TYPE& ptr = foo();
you'll have to type a few characters more, but then again you won't have to repeat your method signatures in 18 different flavours.
pjmlp
On those cases not, but certainly as function parameters.

or class members that are initialized on the constructor and never change during the class lifetime, if they are pointers instead it may raise lifetime questions.

Althought probably the correct way would be to make use of std::observer_ptr<>(), but it still isn't in the standard.

slavik81
> I would rather ask, why did C++ add another reference type next to pointers

References were added so users could create types that look and feel like the built-in types. You need references to implement operator[] for std::vector or std::deque.

Another example would be a vec2 class with a += operator that returns *this, just like the += operator for float.

lmilcin
In my experience, I have to qualify I program "ANSI C", otherwise people assume that I am really talking about C++.

I list ANSI C and no C++ in my professional experience and yet I have had a bunch of people call me to seriously talk about me helping in their C++ project. Maybe I shouldn't fault recruiters too much, though they should probably understand what language they are hiring for. But some of these guys were technical managers.

It kinda seems to me a lot of technical world assumes C died and C++ is newer and better version of it, which obviously is wrong way to look at it. These are separate languages that for unfortunate historical reasons share a lot of tooling and language syntax.

varajelle
> C died and C++ is newer and better version of it

That's kind of my opinion. C didn't die for legacy reasons, but starting new project in C seems a nonsense to me.

C++ just has so many features that makes the development of programs and libraries easier, for almost no extra costs.

bsder
> for almost no extra costs

No way. The mental costs alone are staggering.

My standard observation was that to program C++ properly I always needed an entire shelf of books at hand and I used them daily.

The fact that C++ still can't deliver an FFI/name-mangling/v-table/etc. standard that everybody can agree on tells me that it's too complex.

varajelle
I would argue that you pay a harder mental cost in C because each project has to reinvent its own convention to emulate C++ features, and also because C allow for less abstraction which makes reasoning about the whole program more difficult

I don't see the relation with the fact that msvc and GCC have chosen different c++ ABI. That's not telling anything about the complexity of the language.

flohofwoe
If you feel the need to emulate C++ features in C then you're just writing C code with a C++ mindset.

Getting back to the "C way" takes a couple of months to get C++ out of your system first ;)

Of course for some types of problems, C++ is indeed the better language than C, but very often other languages are even better suited (e.g. I turn to Python for most problem where C doesn't work well, for instance munching text files)

varajelle
I was referring to the things from the video, where RAII and generic types are emulated with complex macros. And where std::string(_view) is re-invented
flohofwoe
Fair point, but cleanup and string handling are hardly problems where C++ has a monopoly, or even particularly good solutions to offer ;)
jstimpfle
You are probably referring to the defer() macro, which is well suited for some cases and not too unergonomic to use. I've used this for multiple years, and I still love it, together with X-macros they are some of the most important tricks I would advice any C programmer to try out.

Sometimes with defer() you might get a difficult to read error message when you're doing something wrong, but it's galactically easier to deal with than the standard STL error spew that so many C++ programmers have just come to accept, and it's hard to do something wrong in the first place (just put simple expressions as arguments).

A comparison of defer() with RAII is not that meaningful, as they are totally different things. RAII is this complicated system that leads to (requires) other more complicated stuff like {default,copy,move,assignment...}{constructor/destructors} as well as exceptions, with all sort of terrible interactions and implicit behaviour, that can easily get out of hand and make your code an unreadable mess and/or produce terribly inefficient (piece-meal allocations/function calls) and slow-compiling code (huge header includes).

In the simple situations where defer() is a win, if you use (just) RAII instead, you always have to declare a class out-of-line first (using weird braces and all) to get ad-hoc behaviour, while with defer() macro you can just make something up on the spot, which is often a better way.

I'm not saying there can't be experienced coders who use RAII well in some situations, but personally I opt to just not use it, since the price seems far to high for the benefits, outside of say primitive use in leetcode assignments.

ogoffart
The problem with defer is that it is a macro with all its problem. Imagine such code

   for (int i = 0; i < files_count; ++i) {
       file_handle_t handle = open_file(files[i]);
       defer(close_file(handle)) {
           // ...
           if (some_condition) {
              close_file(handle);
              break;
           }
           // ...
       }
   }
But this doesn't work because you did not know or you forgot that `defer` was implemented with a `for` inside and so the `break` or `continue` goes out of the wrong loop. and that's just one example of the many thing that can go wrong because it is a macro.

On the other hand, with RIAA, you just have your file_handle that automatically close so you can't forgot to close it, and the rules are well known and not that difficult to understand.

jstimpfle
It's indeed a problem that has happened to me, which is why I like to make the macro like

    for DEFER(init, exit) {
    }
or at least give it a name that indicates clearly that this is syntactically a loop. That's like with some iteration macros that I like to use as well from time to time. The basic idea is to never try to hide what you're doing, since that will backfire. You can still take a balanced approach with DRY and separation of concerns principles, which can lead to reasonable macros.

> and that's just one example of the many thing that can go wrong because it is a macro.

I'm inclined to say that nothing can go wrong in above usage, or at the very least it would take criminal energy to break it (I really can't come up with a case right now).

It's perfectly doable to write safe macros with only a little experience. Follow these simple rules when defining macros: 1) parenthesize usages of macro params, and parenthesize the whole macro body if it is a complete expression. 2) Use parameters that take syntactical expressions only once, to prevent evaluating side-effects (like x++) multiple times.

Linux kernel even allows for declaration of local variables in macros by using expression statement blocks (GCC extension). Although I've never had a need for them, I believe that with this approach you can fulfill rule 2) in all possible situations.

You can improve macro safety in cases where you need to define a macro that is a little dangerous by just capitalizing the macro's name to make clear at the call site to be a little bit careful here. The thing is, there is no need to be 100% safe. It's very good to be 99% safe and have a simple to use mechanism. Because there are always so many other ways to break your programming, and if you're trying to be 100% safe at the cost of being twice as hard to use, that's effectively a net loss because you're provoking problems in other ways.

> On the other hand, with RIAA, you just have your file_handle that automatically close so you can't forgot to close it, and the rules are well known and not that difficult to understand.

Could agree if it's a file handle or something other off-the-shelf thing where you don't have to make the class yourself, and everybody instinctively is aware of the implicit behaviour. Otherwise, I very much like the more explicit behaviour and ad-hoc convenience that a defer() macro gives me.

maccard
> If you feel the need to emulate C++ features in C then you're just writing C code with a C++ mindset.

So you need a C++ mindset to have a use for a dynamic array, a hash table, threads or namespaces, all cross platform? (Yes windows is a platform too)

That's without considering raii! (which does admittedly have some baggage wrt the functions you need to implement.)

flohofwoe
Dynamic arrays, hash tables, threads: C++ doesn't have those either as language constructs, they are only implemented in the standard library.

Namespaces: prefixes work just fine in C and don't require name mangling.

RAII makes no sense with C's concept of "dumb data" instead of C++'s "smart objects".

ogoffart
Why do namespaces require name mangling? One could imagine just using :: in the symbol name.

Anyway, even C has name mangling: For example, on Windows, all C symbols gets prefixed by an underscore https://docs.microsoft.com/en-us/cpp/error-messages/tool-err... And even on macOS there is something about having symbols starting with \1

maccard
Whether it's part of the language or the standard library is arguing semantics; Support for type safe dynamic arrays is something that C++ has that C doesn't, is widely used, and poorly reomplemented in C using macros (if you're lucky).

>Namespaces: prefixes work just fine in C and don't require name mangling.

This is a perfect example of a feature that solves a problem that C has (global namespace pollution). Prefixing is a bandaid, and a nasty one at that. Everyone loves #define NOMINMAX in the windows headers, and prefixing all their code with a faux namespace, dirtying _all_ of the code.

> RAII makes no sense with C's concept of "dumb data" instead of C++'s "smart objects".

Sure it does. Every call to fopen should be paired with a call to fclose, every malloc with a free. RAII practically eliminates a whole category of issues around resource leaks; in over a decade of writing C++ professionally, almost every instance of a memory leak, stomp or resource leak was someone trying to be "clever" and drop down to more C style code.

formerly_proven
> If you feel the need to emulate C++ features in C then you're just writing C code with a C++ mindset.

Ah, classic no true scotsman'ism. No real C programmer would emulate classes, an object system, virtual dispatch, templates, ...

pjmlp
I wish, althought C++ was born on the same building as C (kind of) and has enjoyed first class support on UNIX, it has hardly taken its place at the kernel level or syscalls.

So most UNIX/POSIX projects, even new ones, will default to C.

Then there is the embedded space where almost 40 years later trying to use C++ instead of C is still an uphill battle, between embedded development communities, tool vendors, debugging tools, available libraries.

Arduino and mbed are the exceptions, not the rule.

Even Microsoft despite all their security talk around Azure Sphere, just releases a pure C SDK for it.

Which is while I tend to rant about C, I also argue that tooling improvements related to security are more than welcomed, and knowledge about best practices when coding in C should be more widespread.

It is the COBOL of systems programming languages (about 10 years younger) and it isn't going away for the foreseable future.

throwaway17_17
This is a hope OT reply, but I just want you to know that I truly appreciate your commenting on HN. I find myself actively seeking out your comments when browsing. While I may disagree with some of your thoughts (violently in a few cases) I always find them well written and argued. I even find myself wondering what you would think of my pet language project. So, in sum, even if coming to HN is just a fun diversion for you, it actually makes a difference to some people, so thanks.
rnestler
> Then there is the embedded space where almost 40 years later trying to use C++ instead of C is still an uphill battle, between embedded development communities, tool vendors, debugging tools, available libraries.

I worked in embedded development for over 10 years and at every place it was the norm to use C++ instead of C internally. But when creating libraries for customers to use, these where almost always in C or at least with C bindings.

I guess the reason is that one can use C libraries in C++, but not the other way around.

lmilcin
> Then there is the embedded space where almost 40 years later trying to use C++ instead of C is still an uphill battle, between embedded development communities, tool vendors

And why do you think this is so?

When I was starting with embedded development I missed C++ as I felt compelled to reinvent same things that were given in C++.

But then I grew up to learn there is a hefty price to pay for it and in embedded development those problems are blown due to properties of the environment and types of projects you build.

It is one thing for a game to be constantly crashing and it is another if this is happening to an embedded device.

When you develop embedded code it is way more important to understand exact consequences of your actions and C++ is trying to hide those from you as much as possible.

There are also other requirements like being able to easily ascertain the amount of stack used, ability to use exclusively statically allocated memory, etc. that are conflicting with C++ or at least making it difficult to enforce them in C++.

I am very happy to see Rust is overtaking C++ in embedded and is an answer to C problems without creating (too many) of its own.

pjmlp
It is a culture problem, something that only will change with mentality reboot.

"CppCon 2016: Dan Saks “extern c: Talking to C Programmers about C++”"

https://www.youtube.com/watch?v=D7Sd8A6_fYU

"Writing better embedded Software - Dan Saks - Keynote Meeting Embedded 2018"

https://www.youtube.com/watch?v=3VtGCPIoBfs

"Embedded & C++ - Meeting 2017 Keynote"

https://www.youtube.com/watch?v=mNPfsUZb3vs

In a way, the same kind of subculture in C++ that jumps in cries of horror if you happen to use std::vector/array/string with bounds checking enabled.

lmilcin
I think the basic issue is that C++ want to spend a lot of time focusing on C++ The Language, while C developers mostly want to focus on developing the logic of whatever they are doing.

When I worked on C++ projects half of the discussion was on just the use of language or various consequences of it.

On C projects that never happens. There is nothing to talk about so everybody focuses on making the project better.

Things I don't miss after I switched from C++ to C:

-- discussing compiler feature set,

-- discussing how exactly to format complex C++ constructs,

-- regular calls for help from less experienced devs to more experienced C++ "gurus" for their wisdom to just interpret what the code does or tell them how to write the thing they want to write,

-- trainings for less experienced developers so that they can even understand the syntax of the code,

-- hunting bugs due to lack of understanding of complex internal mechanisms,

-- having hard time working with a debugger on complex code,

-- not being able to tell wtf is the exact type of the thing that I am looking at or what exact code is going to get execute when I use an operator or call a function. The IDE not being able to locate it for me is an added "bonus".

pjmlp
What I miss most when working in C instead of C++ is that although lint was created in 1979, most projects still avoid any kind of static analysis.

Then there are the discussions on:

- what warnings to turn on as errors

- what ISO C says and what compiler XYZ does, with many not even aware to the differences

- not clear understanding of the 200+ UB cases documented on the standard

- in-house libraries for safer handling of strings and arrays

- experienced developers creating CVEs because they think they are free of such errors (pun intended)

citrin_ru
Almost all above applies to C++ too.
pjmlp
It does indeed, with the big difference that C++ community cares to reduce the amount of UB on the standard, and pushes for language features that improve safety.

Now if people choose to ignore the tools available to them, just like they enjoy ignoring lint since 1979, well there is little the doctor can do to save patients that refuse help.

twic
> I think the basic issue is that C++ want to spend a lot of time focusing on C++ The Language, while C developers mostly want to focus on developing the logic of whatever they are doing.

This is just libel, really. There are meta-nerds in C and C++, but there is also a great majority of programmers just interested in delivering good software.

wruza
Ah, right. And all these “my move constructor wasn’t called” — “one of subfields had non-moveable field” and other arcane topics, which only C++ forums have, are just little implementation details. C++ is good when you believe it is Curly Visual Basic with some AOT speed and is an implicitness nightmare when you really care.
pjmlp
That is the beauty of C++.

I can write VB/Delphi like code with C++ Builder, write raytracing algorithms in CUDA, or just have fun targeting ESP32.

Y_Y
Maybe you're just an unusually talented coder, but I pay dearly for every little extra bit of C++ my code touches. It's often worth it, but never a freebie.
varajelle
What are these costs? Performance costs? Most of C++ abstraction are zero costs. There is always the possibility of misusing them, but you can also misuse C libraries. Learning costs? This is compensated by the fact that you don't have to re learn each project convention in C to emulate the same feature. Compile time costs? Yeah, that can be annoying. Costs of more bugs? In my experience, the better type system makes it unlikely.
publicola1990
Yes, also the huge benefits C++ offers in structuring large programs makes it well worth it to switch, even if one does not want the more fancy features of it.
Y_Y
Introducing complexity into the build system, error messages, my mental model, interoperation between different parts of the code, other developers are often unfamiliar with less popular parts of the language, modern stuff especially sucks for portability between compilers and OSes. That's just my experience of course, and it doesn't mean I don't profit from writing and selling cpp-based software every day.
mettamage
I'm distinguishing between a hobby perspective and a professional perspective.

IMO that really depends on the project size and goal of the project. I've written a C++ project of about 1000 lines (algobot trader with some optimized data structures in keeping the order book consistent). I've written it in VS Code, used a GUI debugger and I haven't really paid for anything.

Meanwhile, I have this friend that programs so much C++ that his mantra is "in C++ assume all tools are broken." When I hear his horror stories, oh dear! Heisenbugs come by every 2 to 3 months.

So for small projects that aren't touching the lower OS/systems level parts, you're not paying any extra costs. However, the deeper and further you go, I'd fully agree.

fnord123
Are you sure you're not hitting heisenbugs every 2-3 months?
lmilcin
The issue is for small project you don't really require C++ over C. Because supposedly the price you pay for abstractions has better returns the larger the application is (and that is generally true).

My largest C project was 60k lines of code.

The code was very, very dense. It had a lot of functionality that had to be packed to as little code as possible (due to memory limitation). It had things like transactional log-based database working in very small, static amount of memory, point in time recovery (so if the application failed it could restore itself to a number of possible checkpoints before the failure), parsers for various protocols (BER-TLV, for example), a lot of cryptography and custom cryptographic protocols, a GUI framework for a small monochromatic screen and keypad, drivers for a bunch of devices (thermal printer, external pinpad, etc.), SSL, a lot of business logic, state machines for talking to a network host, etc.

harry8
This is a perfectly valid and fine opinion for many new projects. Possibly even most. The point were I dismiss this sort of thing is where it is "all" new projects.
vadavaski
You probably work with ultra high level stuff, which is the tip of the iceberg when it comes to programming. More than half of what is written around comes from drivers, embedded, engines, robots, controllers and kernel. And for those, you have nowhere to run but to use C down to its bottom. You might use some C++ to enforce some abstraction, iterate in a more fashionable way, but in the end, it's just C
pclmulqdq
Honestly, I think the "killer app" for C++ was generics. If you could write a generic data structure in C without using macros (which are extremely hard to debug), nobody would have wanted C++. However, the Linux Kernel is stuck with AVL trees and primitive hash table algorithms due to complexity, while C++ programmers can blissfully use B-trees and fast linear probing hash maps without worrying about the data structure.
enriquto
> C++ just has so many features that makes the development of programs and libraries easier, for almost no extra costs.

I respect your opinion, but mine is the exact opposite (I don't know how representative mine is, but I'm sure I'm not alone).

The problem with C++ is that many of those "features" are actually "anti-features". From the top of my head: operator overloading, copy-constructors, constructors, destructors, function overloading. While these "features" may make correct code easier to write, they always make incorrect code much, much harder to understand.

For example, you find a simple line of C++ that says "y=f(x);", and it can do anything: has the parenthesis operator been overloaded? and the copy constructor? how many times is a destructor called here? What are its side effects? What instance of f is called, if none of them is defined for the actual type of x? Every single line of C++ that you have to analyze is a terrifying nightmare like this one.

jcelerier
> The problem with C++ is that many of those "features" are actually "anti-features". From the top of my head: operator overloading, copy-constructors, constructors, destructors, function overloading. While these "features" may make correct code easier to write, they always make incorrect code much, much harder to understand.

> For example, you find a simple line of C++ that says "y=f(x);", and it can do anything: has the parenthesis operator been overloaded? and the copy constructor? how many times is a destructor called here? What are its side effects? What instance of f is called, if none of them is defined for the actual type of x? Every single line of C++ that you have to analyze is a terrifying nightmare like this one.

I have yet to see any of this be an actual problem in real-world projects.

I have seen on the other hand a lot of people coming with these abstract "this is gonna be a problem" ideas in mind, and never wanting to touch C again after working on actual modern C++ projects.

madmax96
>I have yet to see any of this be an actual problem in real-world projects

Just on Monday, I was bitten by a bug caused by operator overloading. I'm building a static analysis tool in C++. There's a method `getType()` that returns the qualified type of an expression. I had a call to `getType()` nested in some other calls, e.g. `expr->asAssignmentExpr()->getRHS()->getType()->getSomeQualifiedTypeProperty()`.

The creators of the `QualifiedType` type that's returned by `getType()` had overridden the class member access operator to return an UnqualifiedType. This problem took me an embarrassingly long amount of time to diagnose. The compiler error messages told me that `UnqualifiedType` doesn't have a property `getSomeQualifiedTypeProperty`, but I couldn't see why I was getting an unqualified type from a method that is supposed to return a qualified type. I searched the documentation online, searched the header files, tried reinstalling the library, nothing made sense.

Then, I learned this operator had been overloaded. So, I just needed to write `expr->asAssignmentExpr()->getRHS()->getType().getSomeQualifiedTypeProperty()`.

Ouch.

jcelerier
> So, I just needed to write `expr->asAssignmentExpr()->getRHS()->getType().getSomeQualifiedTypeProperty()`.

with any decent IDE you'd type something like

    expr.as<enter>.get<enter>.get<enter>.get<enter>
and you'd see the following:

https://streamable.com/xib4s0

so I fail to see how this can be an issue if you don't use prehistoric tooling

enriquto
> I have seen on the other hand a lot of people coming with these abstract "this is gonna be a problem" ideas in mind, and never wanting to touch C again after working on actual modern C++ projects.

Well, I for one had the opposite experience. I started programming in C++, and writing, reading and debugging lots of C++ code. It was not "modern" C++, since I stopped doing so around 2006. I embraced C out of personal despair with C++, especially the C++ of other people. For my personal projects, I can still enjoy using "my" favorite subset of C++ (basically, without objects nor pointers, and building the data structures by composing stl containers). Yet, anytime I have to deal with an unknown piece of C++ it is a nightmare. Especially since it is very easy to hide the behavior of the code.

andrepd
Well... What's the difference compared to C? f(x) can also do anything, including side-effects, changing mutable state, etc. Worse if it's a macro.
qdog
In C, n=f(x) plainly means the variable n is assigned the value returned from f(x). While you don't know what f(x) does, you can tell it is a function.

In c++, the = could be a function too, that does unexpected things. Critically, if you are unaware of the side effects of that = operator, you may be doing things you don't want to do. The most likely issue would be performance if you are repeatedly using the = operator thinking it is a simple operation. Like if someone is being clever and uses the Active Record model and you are unexpectedly doing database writes with what you thought was a local object with no side effects.

To not have this happen, of course, you could read the entire object definition, but then you need everyone working on the project to have 100% of the code committed to memory. This is why you will likely find rules in the coding style guide of whatever company banning such practice after someone is bitten by it.

galangalalgol
I have indeed seen horrible things done with overloading andnto a much lesser extent copy consteuctors. But don't forget inheritance or partial template specialization. There are so very many ways to make subtle problems. In C you basically have evil macros and bad casts, which are bad enough.

Are there any languages since C you think have gotten it right?

enriquto
> Are there any languages since C you think have gotten it right?

Basically any language except C++ ? ;)

There's lots of languages that I use and enjoy: lua, julia, octave (just for numerical computation), python (except for numerical computation), the unix shell I find particularly beautiful and elegant (even with its obvious warts). Hell, even javascript the language is mostly OK, if it wasn't for its toxic development ecosystem.

galangalalgol
Do you mean npm and its ability to both facilitate and encourage gigantic dependency trees? I'm worried julia and rust will get lesser versions of that problem.
enriquto
Yes. That's what kills the language for me.
ogoffart
> you find a simple line of C++ that says "y=f(x);", and it can do anything

In practice you know what it does because of the context. Devs don't usually override operator to mean the opposite of their meaning. And in case there are doubts, editors have become pretty good at pointing out at the right location.

It is the same in C. is `y` or `f` or `x` a macro that could potentially have `return` or `goto` statements, that can potentially use a `__LINE__` meaning you can't use two occurrence on the same line or within another macro. if `f` is a function, what are its side effects? Do conversion happen depending on the type of x? Or is it like a va_arg function that need the exact right type?

What i mean is that if you want to obfuscate things, you can do it in C just like in C++. But in normal code it's all pretty obvious.

jstimpfle
It's not that anybody wants to obfuscate things. But with clever mechanisms, people start to notice that they did only when it's too late.

C macros can be useful, I would enjoy programming in this language much less if they weren't there. And if I build a reasonable abstraction with them, it's as little as a grep or go-to declaration to find out the definition. There are no implicit complicated resolution mechanims, no complicated internal data structures that keep what should be application data isolated in the compiler (so it has to be duplicated in other parts of the code). With macros, I just search for the name, and will usually quickly find the definition with very little additional indirection.

harry8
If you can program C well, C++ isn't going to be too much of a problem for you. The reverse is not necessarily true. If I were hiring on a C++ project I'd definitely want to talk to someone who is genuinely good at C - they may not want to talk of course.
user-the-name
Absolutely not. I program C well - very well, I'd even brag - and I've used C++ long ago as well. I've programmed in many other languages besides. I am not adverse to picking up new languages.

But when I look at a modern C++ project, I get instantly overwhelmed. There is so much going on. So many weird features interacting with each other. So much you have to be aware of and familiar with. It is massively painful to work with. I would not be comfortable with working any kind of C++ codebase without years of experience with this absolute beast of a language.

praptak
> If you can program C well, C++ isn't going to be too much of a problem for you.

I only agree that understanding C helps somewhat, e.g. by avoiding the traps of not thinking hard about the underlying memory model. But it won't help you with template metaprogramming or how exceptions can break your supposedly memory-safe code: https://herbsutter.com/gotw/_102/

lmilcin
And that's why I am not claiming I know C++.

Don't get me wrong, I can read the code, debug it and correct it.

But in C++ being able to read the code and understanding consequences of every single line of it are completely different things.

There is just so much magic involved that no one ever can claim they fully know C++ and if they do I can safely and provably call them liars and find something they will not be able to explain.

praptak
My main problem with C++ is not that there's a lot to know (although this too). It's something else: even if you know C++ very well, you need a lot of external research to understand a snippet of code.

A single line of C++ can trigger a lot of mechanisms which change the semantics. Overloaded operators, custom allocation, template overloads, copy vs reference - all of this depending on a huge graph of header files.

lmilcin
I have been programming professionally for over 20 years in languages ranging from assembly to Lisp and everything inbetween and applications from embedded to Linux kernel, to OS, to backend systems to algorithmic trading.

That I don't touch C++ is my choice because after years of development I decided that most of all I value simple and readable code, working with people who like to write simple and readable code or helping projects write simple and readable code. And C++ and community is, in my opinion, anything but about simplicity and readability.

For some reason I do not fully understand, C++ projects I have participated are a contest of who can think of more convoluted C++ construct that nobody ever will be able to understand and C++ seem to be absolutely perfect platform for it.

Even if I am able to understand it (which I frequently do not), I just can't rationalize putting crap like that in a project that is expected to then be grokked and modified by new developers.

I have tried restricting the types of constructs and C++ syntax used in projects in the past but this inevitably causes flamewars and lots of discussions about why these rules were instituted and whether they are necessary. I am sick and tired of explaining the value that exists in moderation and restriction.

Quekid5
> For some reason I do not fully understand, C++ projects I have participated are a contest of who can think of more convoluted C++ construct that nobody ever will be able to understand and C++ seem to be absolutely perfect platform for it.

I think it both a culture and a more technical language problem. There seems to be a sort of extreme "ackshually, ..." one-upmanship and/or pedantry in all the C++ forums I've ever participated in. Of course this is itself driven by the crazy complexity of just the base C++ language itself and the numerous edge cases for everything. I think it's very telling that nobody, not even long-time committee members, can even claims to know all of C++[0].

This is exacerbated further by the committee's unwillingness to remove anything. I mean even such an obsolete feature as trigraphs was only removed in C++17, probably about 15-20 years after it mattered to anybody but IBM with their EBCDIC. Another little fun observation: Initializing a variable can be done in soooo many ways. I think it's at something like 20+ different ways at last count... Not a good sign.

I say all of the above as someone who actually appreciates a lot of things about C++.

[0] Even to a first approximation. Obviously there will always be obscure corners of any practical language such that no human can know literally all of it.

harry8
yep. That's a reasonable view. Hence:

>> they may not want to talk of course.

C++ as an indicator of dud project, poor team and programmer lack of taste is valid. It isn't necessarily always true but there's no reason for you to care if you've gone that way and it worked.

wruza
No upvote can tell how much I relate to this. The only way to get a good maintainable C++ code is to hire very mediocre programmers whose “C++” really means “Qt with some shared ptrs”.

The reason (I believe) is that complex things are like hard drugs for smart people. Instead of solving business tasks, which honestly are often just boring, they long for an art in programming. In C++ this inevitably leads to solving non-existing problems in a most complex, efficient and unstable way that requires a hard set of prerequisites to work, and then these break. You can see it on forums. C, python, js folks discuss libraries, idioms and best practices, and C++ folks discuss a turing completeness of template metaprogramming and the most obscure ways to pass results up the callstack without copying 8 to 24 bytes. Almost no one I talked with there actually worked for someone who actually needed these microscopic gains all over the code. Or who understood what they do beyond “it’s complex and expensive, but in the end they deliver the results we need, so that’s justified”.

jack_h
> The only way to get a good maintainable C++ code is to hire very mediocre programmers whose “C++” really means “Qt with some shared ptrs”.

I feel like this is the most salient point in my mind. You can make an absolute mess of a code base in any language if you re-invent every wheel.

I work in the embedded world and there's a definite trade-off between C and C++. C is very minimal and embedded developers are very reluctant to use any third party code so you end up with a lot of triangular and square shaped wheels so to speak. On the other hand C++ does offer a lot of nice (and appropriate to use) things that would normally be re-invented in a C codebase, however it offers almost too many things which precipitates weird, wrong, and hard to maintain abstractions.

At least in my domain I feel the problem is developers just throwing code at a problem until it compiles and exhibits the expected behavior in the happy path before moving on to the next feature. This leads to the same concept being re-invented multiple times in the same code base in new and exciting ways. After all the goal is not to develop nice abstractions, it's to make a product that can be sold.

I would say C++ is an amazing language for library authors who are necessarily talented and spend the time to create robust, easy to use, and well thought out abstractions that can make the life of an application developer vastly easier.

Of course your mileage my vary as I'm sure the wider software world doesn't have all of the same problems that embedded has. I would just like to point out that I have seen absolutely unmaintainable, disastrous code bases in both C and C++ in my professional life and I doubt any language would have made it better.

lmilcin
> At least in my domain I feel the problem is developers just throwing code at a problem until it compiles and exhibits the expected behavior in the happy path

I specialize in joining projects with "issues", specifically to help them deliver, improve reliability, performance, etc.

I have observed most projects with problems exhibit one of two "failure modes". I mean projects and not developers because projects tend to hire like developers and then developers mostly share same problematic quality. In the end it is not individual contributors who are at fault but management who allowed it to happen.

#1. Insufficient programming skills. This where developers don't use libraries because they don't even know they exist, can't recognize the problem they are solving as generic. This is where they can't structure the code because they haven't seen much code at all and/or are not interested in learning.

You can recognize this immediately as codebases with a lot of code duplication and very weak structure/abstractions.

#2. Too much programming ambition. This is where developers think so highly of themselves that they can't accept existing off the shelf components and will reinvent them because they can do better. They will write new everything because it will offer 10% performance increase in their specific case or just for the intelectual fun of doing it. They will obsess over ensuring there is no duplication of code at the cost of creating baroque structures that have no meaning and purpose other than ensure that every single component works in every single case supported by the application and in any possible future.

You can recognize this as codebases with no duplication but when you try to read the code it seems the structure is so complicated you need to have a huge map on entire wall and a guide to be able to travel the codebase. Most of the objects don't have any meaning in the domain of the problem and are just abstract "stuff" necessary to glue everything together.

I very much prefer working with case #1

The reason is that, as dumb as the code is, you can read it and understand what the author probably had in mind, what the application attempts to do. You can then work with the code, refactor functionality out, and so on.

In my experience case #2 is usually beyond repair (or at least beyond my abilities to repair). These developers become easily hostile -- because they think very highly of themselves they treat everybody as inferior and now I am trying to write some dumb unsophisticated code and so I must be dumb. They also tend to change jobs pretty easily so the only result of trying to fix that kind of project is people suddenly leaving it and management getting restless at the lack of progress.

And for some reason every single C++ team I worked with falls under case #2.

I think because, given so many options, you need to have ambition to willingly choose C++ as your main programming language and so the population is preselected.

Don't get me wrong, these are all highly intelligent people. But you can be very intelligent and still make a mess. I know because I was doing the same until I have acquired some wisdom based on my own mistakes and mistakes I have observed.

pclmulqdq
While this is mostly true, there are some (very limited) circumstances where modern language constructs are legitimately the best approach. Generic libraries are probably the most obvious case where you may need some fancy metaprogramming. Move semantics and other similar tricks for avoiding copies are often used for saving much more than a 24-byte copy.

Unfortunately, a lot of C++ enthusiasts who write this kind of code are language lawyers who might prefer to write in APL (a language with "expressiveness" and "beauty") than a language for humans.

lmilcin
I strongly believe readability trumps everything when it comes to writing code for a lot of reasons.

I love modern language constructs when I can use them to help make the code more readable and verifiable.

What I dislike is using language features to make the code seem more intelligent and eloquent where there already exist simple, dumb, readable way to achieve same result.

whatshisface
The C answer to generics is void pointers, careful programmers, and CVEs. CVEs are the most important C language construct.
lmilcin
https://insights.dice.com/2019/11/27/programming-language-vu...

I think this has reasonable explanation:

“The high number of open source vulnerabilities in C can be explained by several factors,” the organization added in a blog posting. “For starters, C has been in use for longer than any of the other languages we researched and has the highest volume of written code. It is also one of the languages behind major infrastructure like Open SSL and the Linux kernel. This winning combination of volume and centrality explains the high number of known open source vulnerabilities in C.”

So... C++ is there. That it isn't the top of the list is a reflection on the fact that it is rarely used for important stuff.

Nobody registers CVEs for computer games, yet they are predominantly written in C++ and full to the brim with security holes. If what you said was true, these should fare better than C code, and yet they do not.

whatshisface
That's kind of a useless chart for the reason you point out, which is that it doesn't divide by language use.

I think computer games are a bad example because game developers don't care about code quality for their release-once-and-done games.

lmilcin
> The reason (I believe) is that complex things are like hard drugs for smart people.

That is the golden explanation I kind of understood internally but never formulated consciously.

Yes, that's exactly it.

It takes willpower to be able to refrain from all those shiny toys. You see one and you are immediately imagining what you could use it for.

Writing C is like using typewriter or distraction-free editor, putting away your phone and disconnecting the Internet.

Just imagine your team is told to write all their pieces of code in any language they want.

Writing C is like telling the team: sorry, you can't do that. We know all those languages exist and they even may have fancy features that could improve your work, but for reasons of sanity we want you to stay programming single language.

ksec
>The reason (I believe) is that complex things are like hard drugs for smart people.

>That is the golden explanation I kind of understood internally but never formulated consciously.

I am thinking would it be fair to say C++ are for the wicked smart but C are for ones with age old wisdom.

lmilcin
Some more:

Any problem has many possible solutions, but only one (well... few) are simplest.

It doesn't take much intelligence to write complicated code, this is just finding "a" solution.

Finding simple solution requires understanding of range of all possible solutions or at least a lot of them, understanding what makes them simple, and selecting the one that is simplest.

If you are smart and want to show it, why not show your smarts by finding simple solution to the problem?

ksec
One problem is these sort of simple solutions are hard to judge by seniors for your bonus.

Part of Resume Driven Development problem?

Apr 09, 2021 · 4 points, 1 comments · submitted by belter
LucaSas
Speaker here, hope you enjoy the talk.

I also gave an updated version of the talk at embo++ with some small updates and fixes to some code examples, not sure if that will be on youtube but you can see the slides here: https://docs.google.com/presentation/d/1tHdUBWSf8oVbX8Oe4V15...

HN Theater is an independent project and is not operated by Y Combinator or any of the video hosting platforms linked to on this site.
~ yaj@
;laksdfhjdhksalkfj more things
yahnd.com ~ Privacy Policy ~
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.