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 $defined
C3 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%h
ConditionVariable.wait_until
and ConditionVariable.wait_for
readline_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_to
allocator::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_for
Ref
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.