--- layout: post title: Limited "generics" in C without macros or UB tags: [C] --- I should start this post off by clarifying that what I have to show you today is not, in fact, generics. However, it's useful in some situations to solve the same problems that generics might. This is a pattern I've started using to reduce the number of `void*` pointers floating around in my code: multiple definitions of a struct. **Errata**: we rolled this approach back in wlroots because it causes problems with LTO. I no longer recommend it. Let's take a look at a specific example. In [wlroots](https://github.com/SirCmpwn/wlroots), `wlr_output` is a generic type that can be implemented by any number of backends, like DRM (direct rendering manager), wayland windows, X11 windows, RDP outputs, etc. The `wlr/types.h` header includes this structure: ```c struct wlr_output_impl; struct wlr_output_state; struct wlr_output { const struct wlr_output_impl *impl; struct wlr_output_state *state; // [...] }; void wlr_output_enable(struct wlr_output *output, bool enable); bool wlr_output_set_mode(struct wlr_output *output, struct wlr_output_mode *mode); void wlr_output_destroy(struct wlr_output *output); ``` `wlr_output_impl` is defined elsewhere: ```c struct wlr_output_impl { void (*enable)(struct wlr_output_state *state, bool enable); bool (*set_mode)(struct wlr_output_state *state, struct wlr_output_mode *mode); void (*destroy)(struct wlr_output_state *state); }; struct wlr_output *wlr_output_create(struct wlr_output_impl *impl, struct wlr_output_state *state); void wlr_output_free(struct wlr_output *output); ``` Nowhere, however, is `wlr_output_state` defined. It's left an incomplete type throughout all of the common `wlr_output` code. The "generic" part is that each output implementation, in its own private headers, defines the `wlr_output_state` struct for itself, like the DRM backend: ```c struct wlr_output_state { uint32_t connector; char name[16]; uint32_t crtc; drmModeCrtc *old_crtc; struct wlr_drm_renderer *renderer; struct gbm_surface *gbm; EGLSurface *egl; bool pageflip_pending; enum wlr_drm_output_state state; // [...] }; ``` This allows implementations of the `enable`, `set_mode`, and `destroy` functions to avoid casting a `void*` to the appropriate type: ```c static struct wlr_output_impl output_impl = { .enable = wlr_drm_output_enable, // [...] }; static void wlr_drm_output_enable(struct wlr_output_state *output, bool enable) { struct wlr_backend_state *state = wl_container_of(output->renderer, state, renderer); if (output->state != DRM_OUTPUT_CONNECTED) { return; } if (enable) { drmModeConnectorSetProperty(state->fd, output->connector, output->props.dpms, DRM_MODE_DPMS_ON); // [...] } else { drmModeConnectorSetProperty(state->fd, output->connector, output->props.dpms, DRM_MODE_DPMS_STANDBY); } } // [...] struct wlr_output output = wlr_output_create(&output_impl, output); ``` The limitations of this approach are apparent: you cannot work with multiple definitions of `wlr_output_state` in the same file. However, you get improved type safety, have to write less code, and improve readability.