Callback with userdata Zig way

I want my callback to accept the user-code specified parameter (userdata). For example, in C it’s almost always done with void *.
But I can see few ways to do this thing in Zig:

  1. Accept anyopaque pointer
  2. Make code generic by providing type argument

With the first way, I have to cast the userdata parameter inside the function body.

I like the second way (typesafe and no casts), but it looks like it emits duplicate code: Compiler Explorer
Duplicate code will propagate up, and this is kind of a problem for me.

Am I missing something?

If you callback function accepts a pointer, I believe you can cast the function, as ABI wise 2 pointers are interchangeable since they are only integers. EDIT: Assuming all other arguments are the same, only the interpretation of the userdata parameter is changing.

I’ve got the following to compile on Godbolt. I can’t however explain why type erased userdata inlines better than generic callbacks…

2 Likes

I considered adding function pointer casting as a 3rd way, but I see it as bit too hacky :grin: . But your example looks clear, and wrapping the logic inside init() will avoid some problems.
I still want to see what others are going to say, but yours is going to work perfectly for me, thank you!

Casting function pointers opens the door to invisible const casts: Compiler Explorer

If your callbacks are actually comptime known, you can expand on @brodeuralexis solution by generating the cast of the context parameter inside init() instead of casting the function pointer. At least in this simple example the compiler generates the same machine code: Compiler Explorer

1 Like

This is indeed a great addition, thank you!