HNHacker News
TopNewBestAskShowJobs

jefbyokyie

22 karma · joined December 3, 2024

submissionscomments
jefbyokyie··on C: Simple Defer, Ready to Use
> You really should be able to express the required cleanup semantics with "defer"

I'm perfectly able to do that, I just don't want it, because the result is terrible. The syntax no longer shows what happens when and where.

And, if you look at n3434 <https://www.open-std.org/JTC1/SC22/WG14/www/docs/n3434.htm>, you can see the following gem:

> the deferred block may itself contain other defer blocks, that are then executed in chain according to the same rules

This is the worst possible outcome. It means that a continuation passing style sub-language gets embedded in C.

    {
      defer { a(); defer { b(); }; c(); };
      defer { d(); };
    }
At the final closing brace shown, d() will be invoked first, then a(), then c(), then finally b(). Syntactically, the invocations appear in a-b-c-d order in the source code, but the actual execution is neither that nor the inverse d-c-b-a nor the single-level inverse order d-a-b-c.

THAT is an unreadable mess. Good luck debugging that. Not dissimilar to chaining futures in modern async C++ (lambdas deeply nested in lambdas). Which is an abomination.

Your source code syntax is now completely detached from the execution order within a single thread.

Good luck getting that past code review.

Your reference to "no take only throw" makes no sense to me. The gist of that meme is "various characters making contradictory demands". Nobody is making demands here. There's no need for an "explicit alternative". Just don't defer at all, regardless of style. Write the error path / exit path explicitly, using gotos or the arrow pattern.

jefbyokyie··on C: Simple Defer, Ready to Use
> you are in the minority here

Yes, I am.

jefbyokyie··on C: Simple Defer, Ready to Use
> Does C really need this?

No.

> Do languages need to grow in this way?

No.

> The overriding virtue of C is simplicity.

It's no longer simple, especially not with the C11 memory model (which got retrofitted from C++11, and is totally incomprehensible without reading multiple hundreds of pages of PhD dissertations); however, gratuitously complicating C shouldn't be done.

jefbyokyie··on C: Simple Defer, Ready to Use
Indeed!
jefbyokyie··on C: Simple Defer, Ready to Use
> cleanup in every single failure case

you're only tempted to clean up [fully] in every single failure case if you don't know how to implement cascading gotos or the arrow pattern.

jefbyokyie··on C: Simple Defer, Ready to Use
> Invisible jumps are very bad

Agreed; they're terrible. Implicit sucks, explicit rules.

jefbyokyie··on C: Simple Defer, Ready to Use
> number 1 issue I find myself having when switching from C++ to C is missing RAII

That's because you've become complacent; you've gotten used to the false comfort of destructors. C++ destructors promise that you can ignore object destruction in business logic, and that's a false promise.

Assume you have a function that already has a correct traditional (cascading gotos, or arrow pattern) exit path / error path. Assume that you have the (awkward) defer-based implementation of the same function. Assume you need to insert a new construction step somewhere in the middle. In the defer-based implementation, you insert both the new action and its matching "defer" in the same spot.In the traditional implementation, you locate the existent construction steps between which you insert the new construction step; you locate the corresponding existent destruction steps (which are in reverse order), and insert the new destruction step between them. The thinking process is more or less the same, but the result differs: without defer, your resultant source code shows what will actually happen on the exit path, and in precisely what order, and you can read it.

I think defer is awful.

jefbyokyie··on C: Simple Defer, Ready to Use
When constructing an object in C, we may need some permanent sub-objects, and some temporary objects.

If we only need permanent sub-objects, then we set those up gradually, and build an error path in reverse order (with gotos or with the arrow pattern); upon success, the sub-objects' ownership is transferred to the new super-object, and the new super-object is returned, just before the error path is reached. Otherwise, the suffix of the error path that corresponds to the successful prefix of the construction path is executed (rollback). This approach cannot be rewritten with "defer" usefully. Normally you'd defer the rollback step for a sub-object immediately after its successful construction step, but this rollback step (= all rollback steps) will run upon successful exit too. So you need a separate flag for neutering all the deferred actions (all deferred actions will have to check the flag).

If we only need temporaries (and no permanent sub-objects), then (first without defer, again) we build the same code structure (using cascading gotos or the arrow pattern), but upon success, we don't return out of the middle of the function; instead, we store the new object outwards, and fall through to the rollback path. IOW, the rollback steps are used (and needed) for the successfully constructed temporaries regardless of function success or failure. This can be directly expressed with "defer"s. The problem is of course that the actual rollback execution order will not be visible in the source code; the compiler will organize it for you. I dislike that.

If we need both temporaries and permanent sub-objects, then we need the same method as with temporaries, except the rollback steps of the permanent sub-objects need to be restricted to the failure case of the function. This means that with either the cascading gotos or the arrow pattern, some teardown steps will be protected with "if"s, dependent on function return value. Not great, but still quite readable. With defer, you'll get a mix of deferred actions some of which are gated with ifs, and some others of which aren't. I find that terrible.

jefbyokyie··on C: Simple Defer, Ready to Use
> The whole point of syntactic sugar is for the machinery to be hidden

And when the machinery fails, you'll not only have the machinery to debug, but the syntactic sugar too.

jefbyokyie··on C: Simple Defer, Ready to Use
> Not right there, some other place in the function.

Exactly. Both C++ RAII (constructors/destructors) and C23 defer are awful. They make the behavior implicit; in effect they tie an indefinitely large (and growing) baggage to scope termination without the source code reflecting that baggage.

Cascading gotos (or the arrow pattern) are much better. Cleanup code execution is clearly reflected by location in the source code; the exit path can be easily stepped through in a debugger.

jefbyokyie··on Tokyo is set to introduce a four-day workweek for government employees
> You don't owe [...] you might want to

What's the difference? If you don't boost them with all your might, you effectively condemn them to a life of struggle and misery, in today's world. Knowing this, it's gonna be you forcing yourself to give them your all, not society's expectations.

jefbyokyie··on Tokyo is set to introduce a four-day workweek for government employees
> 20% less, maybe 15% net income less ain't that huge of a deal - if it is, something ain't right in your finances anyway

or else, something maybe horribly broken in your country.

I'm happy for you, that you can easily dismiss 15% net income. Try that in Hungary, where generally two full time jobs together are nearly insufficient just to stay afloat.

> One needs to be happy or at least content with its own life to make others happy too, and thats not achievable easily in rat races

Very true, which is why mental health issues are rampant in the Eastern Bloc.

jefbyokyie··on Tokyo is set to introduce a four-day workweek for government employees
Yes, but it matters how much it intrudes on your personal life.

Paying social security (and saving for retirement) when you are young, and getting (some) coverage when you are old, is one thing. It's "only" money.

Having your time, availability, emotional capacity, mental health sucked dry by the elderly in your own family is an entirely different thing. Raising small children is an extreme challenge that requires all your resources; young and middle-aged Japanese are entirely reasonable not to start families.

I recommend reading this:

https://en.wikipedia.org/wiki/Sandwich_generation#Other_chal...

jefbyokyie··on Tokyo is set to introduce a four-day workweek for government employees
What you describe as reciprocation is actually transgenerational exploitation. Be forcefully taken-from when you are young, and then forcefully take (from the young) when you are old.

It should be unidirectional giving. Give to your children, and save for yourself. Retire to an assisted living facility, don't become a burden. Hope to die as soon as you become a burden. If you decide to die, because you are done living, I firmly believe that you can die.

jefbyokyie··on Tokyo is set to introduce a four-day workweek for government employees
Exactly. What sane grandparent would want to live at the cost of cannibalizing their grandchildren? What the sandwich generation received as kids, they need to pay that forward, not back.

For one, I don't want a long life. I want to live as long as I'm not a burden. Don't want to burn down in my final years all that I will have built up for my kids and their kids.

Now, they say that anime is not real life in Japan, and it's true; however it absolutely reflects (I dare say: indoctrinates viewers with) cultural elements of Japan. And this "fuck up your kids' lives so you can take care of your parents" is so characteristic. A good example (of this terrible phenomenon) is in Lovely Complex, where Nobu-chan effectively needs to abandon her sweetheart Nakao-kun, just so she can care for her grandmother, who's about to move to Hokkaido. The most heart-wrenching part is where Nakao and Nobu's grandma sit at the dining table, and Nakao is guilt-tripped into actively encouraging Nobu's grandma to travel to Hokkaido and to rob him of his beloved Nobu. Fuck all that, seriously.

jefbyokyie··on Rust in QEMU Roadmap
> I’m more frustrated that Debian has such a stranglehold on packaging decisions and it effectively refuses to experiment or innovate on that in any way.

What Debian has is not a "stranglehold" but an ideology, and Debian continues to matter to (some) upstream projects because lots of users identify with Debian's hyperconservative, noncommercial ideology.

Your complaint is basically, "it's too bad that the userbase not sharing my values is large enough to matter".

jefbyokyie··on Rust in QEMU Roadmap
C++23 is a godawful mess; especially the functional paradigms (which look beautiful in e.g. OCaml) that got shoehorned kicking and screaming into the morass that C++ had already been.

If you read function specs in the OCaml docs, they're understandable and the syntax is clean; the same concepts bolted onto C++ look like line noise, both in actual syntax and the (allegedy) English-language description on en.cppreference.com.

Reading the C++ standard itself is an exercise in futility, very much unlike the C standard. (Although, latest developments in C land are repulsive too, IMO.)

The C++ committee's tantrums and scandals (physical violence at meetings!) put the worst that has been seen in open-source communities to shame. <https://izzys.casa/2024/11/on-safe-cxx/> has been posted to reddit and HN recently.

C++ compilation still takes absolutely forever, and C++ template error messages are as incomprehensible as ever.

One important problem with C++ (repeated ad nauseam, so this is nothing new) is the unforeseen and unintended harmful interactions between such language features that were supposed to be orthogonal. The only remedy for that is to stop adding stuff to the language; but nooo, it just keeps growing.

Another important problem is that, the more the compiler does for you implicitly, the less you see (and the less you can debug) what happens in the code. This is not a problem in OCaml, which is a managed language with a safe runtime, but it's a huge problem in C++, which remains a fundamentally unsafe language. (And yes, once you start extending OCaml with C, i.e., mixing implicit and explicit, OCaml too becomes unsafe, and a lot of head-scratching can occur.) A home-grown object system in C is at least explicit, so it's all there for the developer to read, instrument, step through, and so on.

When your "core guidelines" <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines> could fill a book, there's a problem with your language.

(I'm not here to defend QEMU's object model indiscriminately; I'm here to bash C++.)

jefbyokyie··on Rust in QEMU Roadmap
> define the base via union of all bases in the chain [...] just checks 3 things in order

Can you please show a concrete example? Thanks.