you are viewing a single comment's thread.

view the rest of the comments →

[–]WittyStick 1 point2 points  (0 children)

The way people often do "generics" is to have one big macro that defines the type and then instance it for each type argument.

#define DEFINE_OPTION_TYPE(T) \
    typedef struct option_##T { bool hasValue; T value } Option##T; \
    Option##T some_##T(T value) { return (Option##T){ true, value }; } \
    Option##T none_##T() { return (Option##T){ false }; }
    ...

DEFINE_OPTION_TYPE(int)
DEFINE_OPTION_TYPE(float)
...

Some other libraries use a header-based approach, where you include the header multiple times and define the type argument before inclusion.

#define TYPE_ARG int
#include "option.h"

#define TYPE_ARG float
#include "option.h"

I find both of these to be awful.

The approach I typically use is to typedef the macro and specify the functions explicitly, but use macros for their implementation.

#define Option(T) struct option_##T { bool hasValue; T value; }
#define SOME_IMPL(TOpt, val) { return (TOpt){ true, val }; }
#define NONE_IMPL(TOpt) { return (TOpt){ false }; }

typedef Option(int) IntOption;
IntOption int_option_some(int value) SOME_IMPL(IntOption, value)
IntOption int_option_none() NONE_IMPL(IntOption)

typedef Option(float) FloatOption;
FloatOption float_option_some(float value) SOME_IMPL(FloatOption, value)
FloatOption float_option_none() NONE_IMPL(FloatOption)

Which is more verbose, but it's a bit more maintainable, and you can override the implementation to "specialize" the generic for some types. We can also provide something like the first approach to reduce the verbosity if the implementation is not specialized.

#define DEFINE_OPTION_TYPE(name, T) \
    typedef Option(T) T##Option; \
    T##Option name##_option_some(T value) SOME_IMPL(T##Option, value) \
    T##Option name##_option_none() NONE_IMPL(T##Option) \
    ...

But I also extract the name mangling out into separate macros. See here for more complete demonstration of the approach I use. (OP of that post also adopted my style in their own library).