2025-08-01
C3 version 0.7.4 brings a substantial set of improvements focused on better enum support, enhanced error handling, improved debugging capabilities, and numerous quality-of-life improvements. And we’re now also releasing binaries for OpenBSD! Here’s a comprehensive look at what’s new.
One of the most significant changes in 0.7.4 is the introduction of const enums.
enum Foo : const, which behaves like C enums but supports any underlying type.ordinal and .from_ordinal methods--use-old-enums to maintain compatibility)C3 0.7.4 introduces two useful new macros for streamlined error handling:
@try: Takes an lvalue and returns a void?. It assigns the value if successful, otherwise returns the error.@try_catch: Extended version that takes an lvalue, an expression, and the expected error value, it will return a bool?.These macros can significantly reduce boilerplate when working with if-catch.
Several compile-time features have been enhanced:
$typeof improvements: Now returns compile-time types in more contexts@is_const introduction: This macro replaces the deprecated $is_const, and is based on $definedC3 0.7.4 continues the focus on improving the developer experience:
foo == BAR; where foo = BAR; was likely intended--echo-prefix for customizing $echo statement prefixes with {FILE} and {LINE} support--list-asm flag: View all supported assembly instructionsthread::fence function provides thread fencing capabilitiesout by default, with temp folders used for command-line builds$embed now accepts absolute pathsauthors field can now be accessed using env::AUTHORS and env::AUTHOR_EMAILS.The standard library now includes several new high-performance hash functions:
string::bformat: New binary formatting capabilities%hConditionVariable.wait_until and ConditionVariable.wait_forreadline_to_stream function for stream-based inputRef and RefCounted experimental typesVolatile and UnalignedRef generic types for typesafe volatile and unaligned references.Version 0.7.4 includes over 40 bug fixes addressing:
Notable fixes include proper handling of null ZString comparisons, correct bounds checking for const ranges, and fixes to complex number operations.
Several features have been deprecated and to streamline the language:
$is_const → @is_const$assignable → @assignable_toallocator::heap() → mem and allocator::temp() → tmem--use-old-enums for compatibility)C3 introduced ordinal based enums in 0.3.0. This allowed the language to support associated enum values and enum → string conversions at runtime with zero overhead. The downside was the lack of support for C enums with gaps. While possible to address with constants or associated values, it lacked the ease of C enums. However, C enums could not be made to properly support things the same things as the 0.3 C3 enums did.
The new “const enum” solves this problem. It works like a distinct type, with constants associated with it. It is defined like an enum, with const added after :. Its behaviour is the same as you would expect from C:
enum ConstEnum : const short{ ABC = 1, BDE, // Implicitly 2 DEF = 100}But the const enums can do things C enums can’t do:
enum Greeting : const inline String{ HELLO = "Hello", WORLD = "World", YO = "Yo"}
fn void main(){ // Prints "Hello" io::printn(Greeting.HELLO); // Inline allows implicit conversion to String io::printn(Greeting.YO == "Yo"); // Inference works like for regular enums Greeting g = WORLD;}Usually in C3, implicit unwrapping is used to convert an Optional to a normal value:
fn void test1(){ int? f = foo(); if (catch err = f) { /* do something */ return; } /* f is unwrapped here */}However, sometimes the assignment may involve an already existing value, in which case we need a temporary:
fn void test2_old(){ int f = abc(); while (some_condition()) { /* use f */ // f = foo(); <- we can't do this int? temp = foo(); if (catch err = temp) { /* do something */ return; } f = temp; /* continue */ }}Having to introduce the temp variable isn’t always ideal, and this is where @try comes in. It conditionally sets a variable if the value isn’t Empty and otherwise returns the error. This allows us to rewrite the code without a temporary like this:
fn void test2_new(){ int f = abc(); while (some_condition()) { /* use f */ if (catch err = @try(f, foo())) { /* do something */ return; } /* continue */ }}Another situation is when you only want to change a value if it’s a non-Empty, it can also be improved:
fn void update_old(){ if (try temp = foo()) my_global = temp;}fn void update_new(){ (void)@try(my_global, foo());}The @try_catch works similar to @try but is useful when you have one expected fault and the other faults should be rethrown. It will also conditionally set a variable, but will return a bool? which is false when the variable is set, true if the expected fault is caught, or an Empty otherwise.
fn void? test3_old(){ while (true) { String? s = next_string(); if (catch err = s) { if (err == io::EOF) break; return err?; } use_string(s); }}
fn void? test3_new(){ while (true) { String s; if (@try_catch(s, next_string(), io::EOF)!) break; use_string(s); }}C3 0.7.4 introduces improved enum support, new error handling macros, and several enhancements to the developer experience. Key additions include const enums with flexible underlying types, direct enum casting, and streamlined error-handling via @try and @try_catch. The release also brings better error messages, improved debugging tools, and expanded standard library features such as new hash functions, Ed25519 support, and virtual memory management. Numerous bug fixes and deprecations aim to improve language consistency and performance. This version marks continued progress toward language maturity and usability.
enum Foo : const. Behaves like C enums but may be any type..ordinal and .from_ordinal.--use-old-enums to re-enable them.$typeof may return a compile time type.--echo-prefix to edit the prefix with $echo statements. Supports {FILE} and {LINE}foo == BAR; where foo = BAR; was most likely intended. #2274--list-asm to view all supported asm instructions.$is_const is deprecated in favour of @is_const based on $defined.env::AUTHORS and env::AUTHOR_EMAILS added.thread::fence providing a thread fence.out by default for projects. Use temp folder for building at the command line.$embed.@try and @try_catch.type and ptr.foo[1:3].$for ct-state not properly popped.r / complex for complex numbers fixed.--max-mem now works correctly again.to_float more tolerant to spaces.$foo variables could be assigned non-compile time values.$foo[0] = ... was incorrectly requiring that the assigned values were compile time constants.@links on macros would not be added to calling functions.Formatter.print returning incorrect size.char[*] b = *(char[*]*)&a; would crash the compiler if a was a slice. #2320@format did not work correctly with macros #2341.return, this fixes #1955.WString.len.@addr macro.ConditionVariable.wait_until and ConditionVariable.wait_forRef and RefCounted experimental functionality.Volatile generic type.UnalignedRef generic type.Check out the documentation or download it and try it out.
Have questions? Come and chat with us on Discord.