Last active
August 29, 2015 13:56
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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