Skip to content

Instantly share code, notes, and snippets.

@tiffany352
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiffany352/8902374 to your computer and use it in GitHub Desktop.
Save tiffany352/8902374 to your computer and use it in GitHub Desktop.
Implementation of option types and option destructuring in C using horrifying hacks. `some`'s comma could probably be cleaned up with a decltype extension.
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#define option(T, name) \
typedef struct option_##name { \
optionhdr hdr; \
T val; \
} option_##name; \
static option_##name some_##name(T val) {\
option_##name opt; \
opt.val = val; \
opt.hdr.ptr = &opt.val; \
return opt; \
} \
static option_##name none_##name() { \
option_##name opt; \
opt.hdr.ptr = NULL; \
return opt; \
}
typedef struct optionhdr {
void *ptr;
} optionhdr;
enum optionenum {
NONE,
SOME
};
void *unwrap(void *ptr)
{
optionhdr *opt = ptr;
if (opt->ptr == NULL) {
assert(false);
}
return opt->ptr;
}
bool is_some(void *ptr)
{
optionhdr *opt = ptr;
return opt->ptr != NULL;
}
bool is_none(void *ptr)
{
optionhdr *opt = ptr;
return opt->ptr == NULL;
}
enum optionenum which(void *ptr)
{
optionhdr *opt = ptr;
return opt->ptr != NULL;
}
#define match(opt) \
for (optionhdr _opt = opt.hdr, run = {(void*)0x1}; run.ptr; run.ptr = NULL) \
switch (which(&_opt))
#define some(T, name) case SOME: for(T *p = (is_some(&_opt)? unwrap(&_opt) : NULL), name = *p; p; p = NULL)
#define none case NONE: for(bool run = is_none(&_opt); run; run = false)
option(int, int)
option_int woop(int i)
{
if (i%2 == 0) {
return none_int();
}
return some_int(i);
}
int main(int argc, char **argv)
{
option_int foo;
if (argc < 2) {
foo = none_int();
} else {
foo = some_int(atoi(argv[1]));
}
match (foo) {
some (int, bar) {
match (woop(bar)) {
some (int, baz) {
printf("%i\n", baz);
}
none {
printf("I'm allergic to even numbers :(\n");
}
}
}
none {
printf("none :(\n");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment