Files

4.2 KiB

Back to Twitter thread index


title: "@NOTimothyLottes I see!" author: "OZ" handle: "@winning_tactic" post_url: "https://x.com/winning_tactic/status/2063733456144597200" post_id: "2063733456144597200" timestamp: "2026-06-07 21:22:52" post_count: 12 reply_count: 0 repost_count: 0 like_count: 0 view_count: 11

@winning_tactic — @NOTimothyLottes I see!

Post 1 (2026-06-07 15:04:23)

Error codes, many APIs get these so wrong. For example aliasing the same code with multiple meaning so the user has zero idea what actually went wrong and what needs fixing. Here is what I do -> thread

Post 2 (2026-06-07 15:07:23) — reply to Post 1

I have a force no-inline exit point which prints ERROR[line]:code Where 'line' is the line number macro LINE passed in from the source, and 'code' is the specific error code. This exits with error code set to 'line'. Thus easy to find termination point in source.

Post 3 (2026-06-07 15:13:52) — reply to Post 2

Function also scales 'line' by 100, and places the version in the lower digits. So know which release version (I'm not doing more than 100 post-release updates). Note all my source is in a single file (including shader source), so I don't need a file in the error print out

Post 4 (2026-06-07 15:19:30) — reply to Post 3

I use force inline macros (I_ in my code) that wrap error checks like testing if a win32 call errors with a null pointer (Err0), and uses builtin expect assuming no error to filter through another no-inline (N_) function to GetLastError and exit if fail, otherwise return pointer

Media 1

Post 5 (2026-06-07 15:21:31) — reply to Post 4

Which means I can simply wrap the calls to WIN32 with a specific Err function and it auto does terminal error checks for cases that shouldn't happen in practice, but if it does happen at least I get instant ability to know where and why

Post 6 (2026-06-07 15:22:51) — reply to Post 5

The defines I use for context

Media 1

Post 7 (2026-06-07 15:26:08) — reply to Post 6

And if this is new, what I do for imports is using a M_(name) macro which imports WIN32 symbols as "void name(void)" functions, which I typecast to the correct type at the exact point of call. Means I don't need any system headers or header like code in my code :)

Media 1 Media 2 Media 3

Post 8 (2026-06-07 15:28:34) — reply to Post 7

At least for WIN32 I do use standard in EXE dynamic linking since Windows doesn't have the Linux .SO nightmare problem. On Linux I only link to libdl and dlopen and dlsym everything else. In theory that gives portability due to ABI and common libdl naming.

Post 9 (2026-06-07 15:30:51) — reply to Post 8

The result of all this is "keeping it simple". For the most part I don't do any runtime dynamic creation of 'things' so all my error checks are init time (low cost) only and fail just results in this common Err() with printed {line,code} exit path.

Post 10 (2026-06-07 17:18:38) — reply to Post 9

Is the error centrally located? e.g. whatever GetLastErr does? I'm motivated to spend some time prettying my own usage, but I keep errors at the call sites, but do a lot of the same action, but the cost is every call is a macro to the real call that handles the rigamarole. green thread based so centrally located is a problem, even though we could do off the curr_tsk register https://gitlab.com/qsrc.net/Lampyr/-/blob/dev/rt/file.h?ref_type=heads#L61 then you have to do this kind of jumping through hoops because no one wants to set it up themselves. https://gitlab.com/qsrc.net/Lampyr/-/blob/dev/rt/mem.h?ref_type=heads#L10 You certainly have a lot of helper macros and single letter api about them, which I like. tasteful yet foreign.

Post 11 (2026-06-07 21:12:08) — reply to Post 10

@winning_tactic These are all for errors that kill the application. GetLastError is like the WIN32 version of error number from libc (figure out why an allocation that returned zero failed).

Post 12 (2026-06-07 21:22:52) — reply to Post 11

@NOTimothyLottes I see!