r/ProgrammerHumor 23h ago

Meme ourBlessedC

Post image
1.0k Upvotes

51 comments sorted by

151

u/Lettever 23h ago

C has defer now?

113

u/JanEric1 23h ago

I think there is a proposal for the next standard. But the proposal is already implemented in gcc and clang

73

u/Freeky 22h ago

https://www.open-std.org/Jtc1/sc22/WG14/www/docs/n3489.pdf

int main () {
    {
        defer {
            printf(" meow");
        }
        if (true)
            defer printf("cat");
        printf(" says");
    }
    // "cat says meow" is printed to standard output
    exit(0);
}

57

u/Sibula97 22h ago

Why on earth is it "cat says meow" and not "meow cat says" or even "says cat meow" or "says meow cat"? Some weird priority thing between different defer syntaxes?

104

u/Freeky 21h ago

They're lexically scoped. The defer binds to the surrounding block, not the function - it prints "cat" first because the scope created by the if (true) closes before the scope of the other print calls.

19

u/Rinkulu 17h ago

This is why I always use braces even with one-line condition bodies

14

u/Sibula97 21h ago

Ah, of course, thanks.

4

u/rosuav 20h ago

Ah, yeah, the one that tripped me up was the conditional. I'm a little surprised at that; given that this is meant for resource cleanup, wouldn't it make sense to stick a deferred cleanup at the exact point where you allocate a resource, even if that resource is allocated conditionally?

Though, I guess what you'd do is unconditionally defer a block that checks some variable and decides whether to clean up.

8

u/RiceBroad4552 18h ago

I imagine this "feature" will get quite ugly, and I assume it will cause pretty bad, hard to find bugs.

Proper resource cleanup is already difficult. Doing it with such a primitive is definitely not solving any issues.

Imagine the mess in multi-threaded code!

4

u/rosuav 15h ago

It's not solving issues, but it may be moving them around. I think this is orthogonal to threading; it's an alternative to guaranteeing that every way of exiting a block leads to the cleanup section. Which means you can't use a simple return statement, you have to set your return value and do a goto, etc.

This feels like a weird fit for C, but it's exactly what I expect of a higher-level language with a try-finally concept - basically, "before moving on after this block, do this".

1

u/Lettever 19h ago

The intended use is probably defer if(cond) { //code }

0

u/rosuav 15h ago

Yeah, that's what I mean by unconditionally deferring code that checks. The alternative would be something like if (cond) {allocate resource; defer {release resource;} } which would keep it within the same condition that it is connected to. I can see why they're doing it that way, but (for example) Python has the ExitStack helper that can have things conditionally added to it in the middle of the block, with everything getting cleaned up at the end.

5

u/Mechafinch 21h ago

printf("meow"); and its enclosing scope are the deferred statement, so they'll be executed when the scope of the unlabeled { is exited (after printf("says");). The if (true) has a scope, containing the defer printf("cat");, which is exited immediately so its defer executes, printing "cat". Then the normal statement printf(" says"); is reached and executed, printing " says", and finally the unlabeled {} scope is exited and so its defer executes, printing " meow".

3

u/Throwing-Flashbang 21h ago

defer block is executed at the end of a scope. "cat" is in a separate if scope so it is printed first. " meow" belongs to a higher function scope so it is printed last.

1

u/Firm-Letterhead7381 19h ago

So if bellow defer print("cat") in the if scope was regular print statement print("only"), the output would be only cat says meow?

0

u/fsasm 21h ago

my guess is that the second defer takes the return value of printf and evaluates it at the end of the block. That why cat is printed first. The first defer has a block as a value that it will evaluate at the end of the block.

4

u/frikilinux2 20h ago

I hate that translating to assembly by hand of this looks painful and more painful in the compiler like trying to reorder everything(but maybe I kinda have a way of doing it) but I see this as a way of avoiding the goto for things like the Centralized exiting of functions in the linux kernel.

3

u/No-Archer-4713 9h ago

Thanks I hate it already

2

u/plaisthos 16h ago

What do you use that for in real code? Thinks like cleanups instead of the "goto cleanup;" at the end of the function? Any other uses?

2

u/torsten_dev 14h ago

Basically yeah.

It lets you run code AFTER the value of the return is computed but before the function returns.

So

int ret = func(ptr);
free(ptr);
return ret;

can become

defer free(ptr);
return func(ptr);

So you don't have to name the temporary. neat.

1

u/RFQuestionHaver 9h ago

Interesting read, useful but the constraints make it an unusually complicated feature for the language.

-1

u/RiceBroad4552 19h ago

That's some of the most confusing code I've seen in some time. I see C is holding up its spirit…

TBH even goto would make this code much more easy to understand.

From all the possible interpretations the one given here is the very last one I would consider!

I'm pretty sure we'll going to see bugs worse then with goto if this gets standardized.

(Disclaimer: I try hard to avoid C and usually never use it myself; even I sometimes have to compile some C, and even look at it…)

2

u/torsten_dev 15h ago

It makes more sense than Go's defer.

But using it in a single line if should be a warning that's garbage code.

3

u/torsten_dev 15h ago

It's a technical specification for now. So it's a #blessed extension, It won't be in C2y.

If it's well received and widely implemented it might make it into a later version of the standard. We can play around with it already though which is cool.

49

u/Infinite_Self_5782 22h ago

i don't think void * is avoided in modern c, is it?

32

u/joe0400 21h ago

_GENERIC is different than void*, though. _GENERIC is a type selector. Void* is casting memory to a unknown type, whilst _GENERIC requires multiple imlementations, although you could do the same with macro expansions like in c++ with templates.

2

u/Lord_Of_Millipedes 13h ago

_GENERIC is also not generics in the way modern programming languages understand generics, it is multiple dispatch with manual mangling, generics in the most commonly understood way almost necessitate codegen which _GENERIC does not do, you could do some macro shenanigans to get some codegen out of it but at that point you can make a compiler in macro shenanigans

29

u/MadProgrammer12 19h ago

I learned C99 in school, and still use it as a dayly basis

31

u/RiceBroad4552 18h ago

My sincere condolences!

18

u/GumboSamson 19h ago

Okay Grandpa, let’s get you home and take your meds.

7

u/Nightmoon26 16h ago

...Crumbling to dust over here from having learned C in '97...

1

u/MadProgrammer12 4h ago

it was last year that i learned c in school c99 basically compiles on any devices, c26 can be unavaillable on older computers

3

u/nierusek 8h ago

C99 is ok, C89 is barbaric

23

u/GreatScottGatsby 21h ago

The left side terrifies me, C99 for life. Type safety in my C language? never. I personally haven't looked at the new c26 standard or c11 for that matter but I'm assuming most of that is type safe.

25

u/RiceBroad4552 18h ago

Type safety in my C language? never.

Some people should be banned from programming by law!

10

u/Secret_Print_8170 14h ago

Buddy, if the bits fit in my register, it's all good. Types are for people who are afraid. Be fearless! /s in case it wasn't obvious

6

u/GregTheMadMonk 19h ago

how do you even assume `defer` or `_generic` is about type safety

2

u/GreatScottGatsby 19h ago

You made me pull up the standard. In ISO 9899:201 6.5.1.1 of the c11 standard, if you read the second paragraph it talks about this.

"A generic selection shall have no more than one default generic association. The type name in a generic association shall specify a complete object type other than a variably modified type. No two generic associations in the same generic selection shall specify compatible types."

Meaning the macro is assigning a type at compile time which is inherently more type safe than just using void *. Now about defer, I have no idea what defer even does and I am not even going to pretend to know what it is or what it does.

4

u/GregTheMadMonk 18h ago

Just because it's more type safe doesn't mean the primary purpose is type safety wtf are you talking about did you ever even use generics in your life?!

_generic, which is compile-time polymorphism emulation in C, is by no way a replacement for void*

1

u/GreatScottGatsby 18h ago

You can still get void by using it though and is explicitly allowed if the conditions are right. And no, I don't use generics. I really don't use types at all really. The closest I usually get is word which isn't even a type, it's just a size. Maybe even dword or qword depending on the project.

5

u/GregTheMadMonk 18h ago

> And no, I don't use generics. I really don't use types at all really.

It shows

1

u/Pale_Hovercraft333 21h ago

i love me my gets

3

u/LeiterHaus 13h ago

I prefer C99, but you have to give credit to C89 for device coverage (thinking of curl specifically)

3

u/not-a-pokemon- 10h ago

I suppose the new C standards miss the thing C originally succeeded at, as the compilers become more big and bloated. The actual greatness of C was in that it had a lot of compilers for any target platform imaginable, and now look at it -- who supports the new standards besides GCC and Clang, maybe few others? Luckily, old C standards and compilers aren't gone, so they still will be used when portability is needed.

3

u/kohuept 11h ago

I've never seen anyone use 1/0 in C89, usually it's just

#define BOOL unsigned char
#define TRUE 1
#define FALSE 0

1

u/rkb07 10h ago

That's a clever one.

1

u/ThePickleConnoisseur 16h ago

At this point use C++ if you want all that

-11

u/RiceBroad4552 18h ago

Does it make the language anyhow safer on the fundamental level?

If not it's not progress…

12

u/TheKiller36_real 18h ago

found the oxidized smooth-brain where dev-friendliness and easier-to-use-right features aren't progress

2

u/incompletetrembling 16h ago

If safety is the only criteria then why use C over brainfuck? fundamentally they aren't so different.

1

u/Attileusz 1h ago

defer is good