I'm building a small demonstration of a stack in C. As C has no exceptions, I'm trying out the result pattern (similar to Result<> in Swift 5) to deal with errors in creation, push, and pop.
I've created a header file that includes an error enum:
typedef enum {
no_error,
illegal_stack_capacity,
out_of_memory,
stack_element_too_large,
stack_full,
stack_empty
} stack_error;
a struct for the stack itself (I am using a stack of strings for concreteness, because at this point I am simply experimenting:
typedef struct {
char** data; // array of strings, capacity set on create()
int capacity; // have to store this separately!
int top; // index of next slot to fill, also the size
} stack;
and now to capture errors, I thought I would build a little struct that has an error part and a success part. As I am experimenting, I tried to have the error part do double duty as both a discriminated union tag as well as capture the error. This may be a hack, but it leads to (what I think is maybe) an interesting question.
typedef struct {
stack_error error;
union {
stack* stack; // because create() returns a stack
char* value; // because pop() returns a string
};
} result;
For reference (and sorry for the clutter), I have these functions:
result create(int capacity);
int size(const stack* s);
bool is_empty(const stack* s);
bool is_full(const stack* s);
stack_error push(stack* s, char* item);
result pop(stack* s);
void destroy(stack** s);
Now the question is that every time I build a result object, the C compiler seems to always assume the anonymous union component of my result struct is supposed to be a stack*. When I write, in my create function
return (result){no_error, s};
the compiler is fine with it, but when I write this in my pop function:
return (result){no_error, popped_value};
the compiler gives me a warning:
boundedstack.c:57:31: warning: incompatible pointer types initializing
'stack *' with an expression of type 'char *'
[-Wincompatible-pointer-types]
return (result){no_error, popped_value};
^~~~~~~~~~~~
I know I can get around this by (1) making the union not be anonymous or (2) creating separate types for stack_result (for create) and string_result (for pop), and maybe I should do that, but I am intrigued by this warning was wondering if any C language experts would know if anything in the language dictates that kind of warning, or if the warning was simply a decision by the compiler implementers to say "hey well I am just going to assume the proper type for the union is the first one I see". The code works just fine, but it seems to me the compiler could have done a better job. Or could it have? Could the compiler have done a better job? Or would it be too expensive of a check in the compiler?
(I really don't want to suppress warnings, as that is bad practice. Am I wrong to have tried the anonymous union?)