Macros

I am really concerned about the (ab)use of macros here. The three different defines for static make no sense at all, a good C programmer knows what static means under which circumstances. But even the best C programmer will not know what global_variable, local_persist or internal means without looking up the macro. (Also calling a static "global_variable" makes no sense at all, because it is not global). This makes it harder for anyone who knows C, because basically here the preprocessor is used to turn C/C++ into a different programming language. Virtually every C/C++ style guide I know forbids doing that for a good reason.

The second set of macros I don't agree with are GAME_UPDATE_AND_RENDER and GAME_GET_SOUND_SAMPLES. It again hides what the code actually does and the programmer will have to look up this macro to see what parameters are actually passed to those functions and what they are called. This is used only twice, so we don't gain much by having only one place to change the parameter list at, but we lose a lot in clarity what the code actually does.

Using macros to define constants I can live with, even though it has its dangers. When doing any calculations while defining them one has to remember to put parentheses around them. Also I don't think that constants not having a type is an advantage. Constants are meant to be used in a certain context which usually also includes a fitting type. So if the constants have that type the compiler can warn if they are used inappropriately.
Hi 5sw,

so you don't agree the reasons casey was explaining when using those macros?
Definitely not with global_variable, local_persist and internal.

For GAME_UPDATE_AND_RENDER I must have missed the explanation. Can you remember on which day this was explained? I will watch that video again, but I don't think there could be any explanation that would make me think this a good idea.
okay so you saw macros and said "Blasphemy!"
5sw
Definitely not with global_variable, local_persist and internal.

For GAME_UPDATE_AND_RENDER I must have missed the explanation. Can you remember on which day this was explained? I will watch that video again, but I don't think there could be any explanation that would make me think this a good idea.


It was on day 3 https://forums.handmadehero.org/j...videos/win32-platform/day003.html at 17:00
@insanoflex512 Nope, not at all. Was there anything unclear in my explanation why I don't like those macros?

@Rooc Thanks.

Edited by Sven on
The macros for dealing with function pointers I can somewhat understand. With their current use, they don't gain us much, but Casey already alluded to using the same technique in other places where the function signature is used dozens or more times. Having a central location to change the signature could be convenient then.

Giving other names to "static" is another matter. For one, static does the same thing for functions and file-level variables. It's a directive to the linker that the symbol will only be visible inside the current translation unit. You can make a non-static global variable (in which case you should declare it as "extern" in a header file), it just so happens that most global variables are declared as static so that they really aren't "global", but local to the current translation unit (usually just the source file they are used in).

The macro for "local_persist" is... ok, I guess. Still, I don't really see the point. Especially for beginners, it just leads to more confusion. Those that learn C primarily from Handmade Hero might have trouble with the naked statics they will encounter in other projects. And those that jump into Handmade Hero's source code now or in the future will inevitably see that weird "local_persist", type it into Google and come up empty.

Yes, "static" is an overused keyword. But so is "void", for example. It's used for "no return value", "untyped pointer" "empty argument list" and more. In my opinion, beginners should be taught to recognize ambiguous keywords in their proper context without hiding it behind non-standard macros.

PS: I feel a bit bad for mostly chiming into discussions criticizing this or that. Casey, if you are reading this, I think you are doing an incredible job, both from an educational and a technical standpoint.
insanoflex512
okay so you saw macros and said "Blasphemy!"


:lol:
As mentioned Casey already addressed this - he is trying to communicate intent. The important thing to keep in mind here is that, when using a unity build, a static variable is a global variable because all the code gets dumped into a single translation unit (technically two in this case).

As far as being confusing, all large projects develop there own "accent" - this is not the first time I've seen someone use macros to make the language "better" from their perspective and I doubt it will be the last. You jump to the definition the first few times, perhaps muttering under your breath, then you've got it and move on.
5sw
@insanoflex512 Nope, not at all. Was there anything unclear in my explanation why I don't like those macros?


Yeah, basically, you didn't really learn why he did it, you just said it was macro abuse. I do agree I don't like the "global_variable", "internal", "local_persisit" thing, but I don't see it as abuse.
Nimbal
The macros for dealing with function pointers I can somewhat understand. With their current use, they don't gain us much, but Casey already alluded to using the same technique in other places where the function signature is used dozens or more times. Having a central location to change the signature could be convenient then.


Yes, this makes it easier to write. But code is written once but read many times more. And these macros make the code objectively harder to read. When you read a function defined with such a macro you don't know which parameters it is getting. So inside the code if a variable is used you have no idea if it is a parameter or some global variable. You always have to check the macro first, which usually is nowhere near the function definition.

And that's not just a problem for new developers getting to that code base. Even the developer who made those macros will have forgotten the details a month or even a year later.
[quote=5sw]
When you read a function defined with such a macro you don't know which parameters it is getting.

On second thought, I fully agree with you that those function signature macros aren't really useful. Not even for the purpose that Casey outlined (conveniently changing the signature of many functions after the fact). If you have full control over the function signature, i.e. it's not imported from a third-party DLL or similar, you could have a single struct as argument (and / or return value). Change the struct, and the "signature" of all functions changes with it.
Two things here:

1) The reason for #define'ing multiple statics has nothing to do with readability, it's for _searchability_. This is very important so you can verify that you have no static storage in DLLs, for example, or statics defined anywhere in multithreaded code. Since "static" would appear everywhere on function signatures, if you use it for all three things, you lose the ability to do automated checks like this, which is very, very bad. Since it costs nothing to #define and use these, and I would hope any reasonable programmer would not take a long time to learn to read them, I think it is not only a good idea but actually an essential idea. I should probably add one more thing, when I remember, which is to #define static to be something else so you can never type it.

2) The reason not to use a struct to bundle parameters to inbound functions is that it is less efficient both for you (more typing) and for the code (you now have to pack everything to be lined up in memory every time before you call it), and then you have to pack everything up again into the return value when you're done. Plus, even if you do this, you have not actually solved the problem, because the structures do handle the part about the function signature, for example if it needs to be __declspec'd or something similar. So it is a strictly less powerful, less efficient alternative. That may not seem like a big deal when we only have a few callbacks, but in more scaleable scenarios it is very important.

- Casey

Edited by Casey Muratori on
I didnt even think about the searchability thing, makes alot of sense to me. Maybe I'll start using it too now.
cmuratori
Two things here:
I should probably add one more thing, when I remember, which is to #define static to be something else so you can never type it.

I think you missed static declaration in function body.