2025-04-30
0.7.0 was supposed to be THE big change this year, but 0.7.1 is actually quitely introducing some very important features.
Operator overloading has been added to help games and maths programming, a previous blog goes into more depth, below is a short overview.
The @operator
attribute defines the overload for Vec + int
To define something like int + Vec
there are two additional attributes added:
@operator_s
(“symmetric operator”) allows either type to go first.@operator_r
(“reverse operator”) requires the second term to be the first one in the arithmetic expression.Overloading with the @operator
overload attribute:
// Defining a simple add: "Complex + Complex"macro Complex Complex.add(self, Complex b) @operator(+){ return { .v = self.v + b.v };}// Define the self-modifying +=: "Complex += Complex"macro Complex Complex.add_this(&self, Complex b) @operator(+=){ return { .v = self.v += b.v };}
Overloading with the @operator_s
symmetric overload attribute:
// This defines "Quaternion * Real" /and/ "Real * Quaternion"macro Quaternion Quaternion.scale(self, Real s) @operator_s(*){ return { .v = self.v * s };}
Overloading with the @operator_r
reverse overload attribute:
// This defines "Real / Complex"macro Complex Complex.div_real_inverse(Complex c, Real r) @operator_r(/){ return ((Complex) { .r = self }).div(c);}
An important step towards correctness is that @require
contracts for
functions are now inlined at the caller site in safe mode. This has always
been a thing for macros, but now this works for functions as well.
This means simple errors can be caught by the compiler, such as using a null pointer where it wasn’t allowed or passing a zero where the argument:
<* @require a > 0 : "The parameter cannot be zero"*>fn void test(int a){ ... }
fn void main(){ // Compile time error: contract violation // "The parameter cannot be zero" test(0);}
This is just the start. C3 will increasingly use more static analysis to check correctness at compile time.
@if
attributes now work on locals and aliases defined using alias
can now be @deprecated
.
0.6.9 and 0.7.0 introduced ways to let an enum convert to its associated value:
enum Foo : (inline int val){ ABC = 3, LIFF = 42}
fn void main(){ int val = Foo.LIFF; // Same as Foo.LIFF.val}
Still, converting from such a associated value to an enum used the rather unknown @enum_from_value
macro.
To make this more convenient, enums gain two new type functions .lookup
and .lookup_field
:
lookup(value)
lookup an enum by inlined value.lookup_field(field_name, value)
lookup an enum by associated value.fn void main(){ Foo? foo = Foo.lookup(42); // Returns Foo.LIFF Foo? foo2 = Foo.lookup_field(val, 3); // Returns Foo.ABC Foo? foo3 = Foo.lookup_field(val, 1); // Returns NO_FOUND?}
String str = ""
was not guaranteed to return a pointer to a null terminated empty string, unlike ZString str = ""
. This was a little inconsistent, so both return the same thing now.foo[..] = bar
would sometimes mean copying the right hand side to each element of foo
and sometimes it meant a slice copy. Now semantics have been tightened: foo[..] = bar
assigns to each element and foo[..] = bar[..]
is a copy.c3c build
now picks the first target rather than the first executable.Following this release, the focus will be on improving the standard library organization. New guidelines for submitting modules have been adopted to ensure that the implementation can be worked on without having to be tied to a pull request. Right now an updated matrix library is actively worked on.
There is also a new repo for uncurated C3 resources, where anyone can be showcased: So if you have a project you want to share – do file a pull request.
@require
checks are added to the caller in safe mode. #186+ - * / % & | ^ << >> ~ == != += -= *= /= %= &= |= ^= <<= >>=
@operator_r
and @operator_s
attributes.sincos
, ArenaAllocator
, Slice2d
.@deprecated
.@if
on locals.Foo { 3, abc }
#2099.Foo[1..2] = { .baz = 123 }
inference now works. #2095foo[1..2] = bar[..]
rather than the old foo[1..2] = bar
. The old behaviour can be mostly retained with --use-old-slice-copy
).Enum.lookup
and Enum.lookup_field
.c3c build
picks first target rather than the first executable #2105.@if
now does implicit conversion to bool like $if
. #2086@if
was ignored on attrdef, regression 0.7 #2093.@ensure
was not included when the function doesn’t return a value #2098.@clone_aligned
and add checks to @tclone
%s
would not properly print function pointers.assert
#2108.@ensure
should be allowed to read “out” variables. #2107math::I
and math::I_F
for math::IMAGINARY
and math::IMAGINARYF
the latter is deprecated.array::contains
to check for a value in an array or slice.Check out the documentation or download it and try it out
Have questions? Come and chat to us on Discord.