DEV Community

Jack Delahunt
Jack Delahunt

Posted on

Fixing C++ by making unions better

In the past, I have gone through some of my issues with C++ and how I think I can improve the language. To do this I am currently creating my own language called ‘Liam’. I have gone over basic syntax and features in a past post here but today I am focusing on the new “Typed Unions” feature.

A full walkthrough of this in video form is on my channel here.

We have all experienced the deeply nested hierarchies of Object-Oriented Programming and asked ourselves “Is there a better way”? Well, I think C++ and as inherited from C already had a pretty good answer.

For me at least the vast majority of my inheritance comes down to wanting to group many different types into one with some common members or functions across them. For example, in Liam I have a ‘Statement’ struct that is inherited by many other statement types like ‘IfStatement’, ‘ScopeStatement’, and so on. It is nice to bundle these up and refer to them as just ‘Statement’ as I may not need or care about what I am referring to.

You can somewhat simulate this in C with the use of a union containing many structs and having some id of which type the union is currently.

struct Statement {

    StatementType type;

    union {
        IfStatement if_statement;
        ScopeStatement scope_statement;
        LetStatement let_statement;
    };

};
Enter fullscreen mode Exit fullscreen mode

This gives the same functionality of inheritance but there is one issue, you must always check the if of the statement. While this is not normally unsafe it can lead to problems like when not initializing the type still gives a valid value.

To try and help with this I added Typed Unions to my language and here is how they work. You can see in the image below the type specifier for ‘x’ is multiple types separated by a pipe denoting and or semantic.

fn main(): void {
    let x: u64 | bool | str = "hello sailor!";
}
Enter fullscreen mode Exit fullscreen mode

This shows the value of x might be a number, a boolean, or a string but it is not known for sure. This can also be extended to struct types to replicate the behavior in C’s unions. But there is still one more thing and that is how to get the actual value from x in a type-safe way.

fn main(): void {
    let x: u64 | bool | str = "hello sailor!";

    if x is str as_string {
        println[str](*as_string);
    }
}
Enter fullscreen mode Exit fullscreen mode

All you do is a ‘is expression’, this just returns true if the value currently stored in the variable is the one we are asking, and if so it gives us a pointer to that value which in this example is the ‘as_string’ identifier. This new identifier is also scoped to the if block meaning this can be repeated for multiple types.

Another area in which this is useful is error handling. I personally really love how Zig does error handling and these new Typed Unions can get us that.

fn main(): void {
    if add(10, -20) is u64 n {
        print[u64](*n);
    }
}

fn add(x: i64, y: i64): u64 | str {
    let result := x + y;
    if result < 0 {
        return "Error negative number";
    }
}
Enter fullscreen mode Exit fullscreen mode

This example is a bit more involved but you can see that the return of my add function is now either a number or a string where the string is my error message. I can then check if my function call was completed by using the is expression shown before.

If you like this post or want to contribute to the language go and check it out on github here.

Top comments (3)

Collapse
 
pgradot profile image
Pierre Gradot

Say hello to std::variant : en.cppreference.com/w/cpp/utility/...

Collapse
 
pauljlucas profile image
Paul J. Lucas

I came here to post the same thing. It's generally a good idea to see what new things newer versions of C++ have added before you go off an re-invent the wheel.

Collapse
 
jackdelahunt profile image
Jack Delahunt

Hi, I am aware of std::variant and its even what is currently being used for code generation until I add my own implmentation.

However noticing similar features in this language to what cpp already has is not reinventing the wheel. While yes std::variant is a thing good luck using a custom allocator for the c++ stdlib. What about how impossible it is to actually debug c++ stblib types?

C++ has some nice things but no amount of feature creap until C++4X will fix some problems I have with it.