Hacker News new | ask | show | jobs
by kevin_thibedeau 687 days ago
C11 does with _Generic but it is limited in ways that make min/max implementations flaky.
2 comments

Even with _Generic you can't declare generic functions. You'd still need a macro call that uses _Generic to dispatch different implementations depending on the parameter types.
Generic dispatching all the type combinations (or warning or erroring) wouldn't be a problem in a project the scale of the Linux kernel.

I'm unfamiliar with the incantations needed to try preserve constant expressions though, that might be too much for them.

The concrete problem that the kernel is facing is an exponential growth of macro expansion. Any current solution, safe or not in terms of re-evaluation, needs at least two copies of both arguments to be expanded [1], so expressions like `min(min(a, b), c)` will expand some arguments four times. The growth factor would be much larger than two if the definition wasn't carefully designed to avoid such cases.

[1] `_Generic` also requires at least two because you need one copy to select the generic implementation and another to call it. C23 `typeof` (or the equivalent GNU extension) allows for a compact type tuple matching:

    inline static int max_int(int x, int y) { return x > y ? x : y; }
    inline static unsigned max_uint(unsigned x, unsigned y) { return x > y ? x : y; }
    /* ... */

    #define MAX(a, b) (_Generic( \
        (void (*)(typeof(a), typeof(b))) NULL, \
        void (*)(int, int): max_int, \
        void (*)(unsigned, unsigned): max_uint, \
        /* ... */ \
        default: max_type_error \
    ) (a, b))
Also _Generic is intended for a function that takes a single varying type. The kernel's min/max macros allow you to safely mix types.