Skip to content

Instantly share code, notes, and snippets.

@LAK132
Last active December 5, 2023 12:57
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LAK132/0d264549745e8196df1e632d5b518c37 to your computer and use it in GitHub Desktop.
Save LAK132/0d264549745e8196df1e632d5b518c37 to your computer and use it in GitHub Desktop.
Result types in C
#ifndef __cplusplus
# define decltype typeof
# include <stdbool.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#define TOKEN_CONCAT_EX(x, y) x##y
#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_EX(x, y)
#define UNIQUIFY(x) TOKEN_CONCAT(x, __LINE__)
#define Result_EX(T, E) result_##T##_##E##_t
#define Result(T, E) Result_EX(T, E)
#define ResultDecl(T, E) \
typedef struct \
{ \
bool _is_ok; \
union \
{ \
T _ok; \
E _err; \
}; \
} Result(T, E)
#define Ok(V, T, E) \
((Result(T, E)){ \
._is_ok = true, \
._ok = V, \
})
#define Err(V, T, E) \
((Result(T, E)){ \
._is_ok = false, \
._err = V, \
})
#define is_ok(V) (V._is_ok)
#define is_err(V) (!(V._is_ok))
#define if_let_Ok(I, V) \
if (is_ok(V)) \
for (bool UNIQUIFY(once) = true; UNIQUIFY(once);) \
for (decltype(V._ok) I = V._ok; UNIQUIFY(once); UNIQUIFY(once) = false)
#define if_let_Err(I, V) \
if (is_err(V)) \
for (bool UNIQUIFY(once) = true; UNIQUIFY(once);) \
for (decltype(V._err) I = V._err; UNIQUIFY(once); UNIQUIFY(once) = false)
#define unwrap(V) ((is_ok(V) ? (void)0 : abort()), V._ok)
#define unwrap_err(V) ((is_err(V) ? (void)0 : abort()), V._err)
#define get_ok(V) (is_ok(V) ? &(V._ok) : nullptr)
#define get_err(V) (is_err(V) ? &(V._err) : nullptr)
#define map(V, T, E, F) (is_ok(V) ? Ok(F(V._ok), T, E) : Err(V._err, T, E))
#define map_err(V, T, E, F) \
(is_err(V) ? Ok(V._ok, T, E) : Err(F(V._err), T, E))
#define and_then(V, T, E, F) (is_ok(V) ? F(V._ok) : Err(V._err, T, E))
#define or_else(V, T, E, F) (is_ok(V) ? Ok(V._ok, T, E) : F(V._err))
#define flatten(V, T, E) \
(is_ok(V) ? (is_ok(V._ok) ? Ok(V._ok._ok, T, E) : Err(V._ok._err, T, E)) \
: Err(V._err, T, E))
typedef struct
{
int val;
} thing_t;
ResultDecl(int, bool);
ResultDecl(thing_t, bool);
ResultDecl(Result(thing_t, bool), bool);
thing_t make_thing(int v)
{
return (thing_t){.val = v};
}
Result(thing_t, bool) maybe_make_thing(int v)
{
if (v % 200 == 0)
return Err(v == 200, thing_t, bool);
else
return Ok(make_thing(v), thing_t, bool);
}
Result(int, bool) test(bool v, int i)
{
if (v || i == 0)
return Err(v, int, bool);
else
return Ok(i, int, bool);
}
int main()
{
int input1, input2;
fscanf(stdin, "%d %d", &input1, &input2);
Result(int, bool) result = test(input1 != 20, input2);
if_let_Ok(ok, result) { fprintf(stdout, "%d\n", ok); }
else if_let_Err(err, result)
{
fprintf(stderr, "%s\n", err ? "true" : "false");
}
Result(thing_t, bool) thing = map(result, thing_t, bool, make_thing);
if_let_Ok(ok, thing) { fprintf(stdout, "we got a thing %d\n", ok.val); }
Result(Result(thing_t, bool), bool) maybe_thing =
map(result, Result(thing_t, bool), bool, maybe_make_thing);
Result(thing_t, bool) flattened = flatten(maybe_thing, thing_t, bool);
if_let_Ok(ok, flattened)
{
fprintf(stdout, "we got a flattened thing %d\n", ok.val);
}
Result(thing_t, bool) and_thend =
and_then(result, thing_t, bool, maybe_make_thing);
if_let_Ok(ok, and_thend)
{
fprintf(stdout, "we got an and_then'd thing %d\n", ok.val);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment