C3 0.8.0 The Core Language Is Settling - C3 Programming Language Skip to content
Initializing search
Language Overview<br>C to C3<br>Language Fundamentals<br>Language Common<br>Generic Programming<br>Build Your Project<br>Language Rules<br>Misc Advanced<br>Implementation Details<br>Standard Library<br>FAQ
Get Involved
Thank You
Blog
Single Page Docs
Enums and constdef<br>Operator overloading<br>Compile time enhancements<br>Contracts<br>Generics<br>Syntax changes<br>Toolchain changes<br>Stdlib changes<br>Fixes<br>Summarizing<br>Thank yous
C3 0.8.0 The Core Language Is Settling<br>C3 is a programming language that evolves C – the same low-level model but with modern ergonomics. With 0.8.0, we're getting our first real glimpse of what C3 1.0 will look like: the core language design is now locking into its final shape.<br>Two changes are big enough to deserve their own posts. The compile time reflection system has been reworked into its final form — and in the process we got to kill off half the builtins: link. And we're making the move to signed by default, correcting what turned out to be a five-year mistake: link.<br>As with all 0.x.0 releases, we've tried to collect all the breaking changes into this single release, so the rest of the 0.8.x line can stay backwards compatible.<br>Aside from the reflection changes, these are the major changes:<br>Distinct types¶<br>Distinct types now defaults to be "structlike"¶<br>0.7.4 introduced the concept of @structlike which meant a distinct type could not implicitly convert from a literal. With 0.8.0 we flip the defaults: by default distinct types do not convert from literals, but with @constinit they do:<br>// 0.7.4<br>distinct Foo7 = int;<br>distinct Bar7 @structlike = int;
Foo7 f = 1; // Ok<br>// Bar7 b = 1; ERROR!<br>Bar7 b = (Bar7)1; // Ok
// 0.8.0<br>distinct Foo8 @constinit = int;<br>distinct Bar8 = int;
Foo8 f = 1; // Ok<br>// Bar8 b = 1; ERROR!<br>Bar8 b = (Bar8)1; // Ok
Often people were assuming "structlike" behaviour, cause accidental bugs. For this reason we flipped the defaults.<br>Enums and constdef¶<br>No more +/-¶<br>Doing addition on enums is no longer possible:<br>// 0.7.4<br>MyEnum foo = BAR;<br>MyEnum baz = foo + 1; // OK!
// 0.8.0<br>MyEnum foo = BAR;<br>// MyEnum baz = foo + 1; ERROR!<br>MyEnum baz = (MyEnum)(foo.ordinal + 1); // OK
Enhanced ++/--¶<br>Enums still support ++/-- and get implicit wrapping when overshooting the ends: enum MyEnum<br>ABC,<br>DEF,<br>GHI<br>fn void test()<br>MyEnum e = ABC;<br>e++; // e is now DEF<br>e++; // e is now GHI<br>e++; // e is now ABC through overflow wrapping<br>e--; // e is now GHI through underflow wrapping
Removed inline enums¶<br>To simplify the language, inline enums were dropped.<br>// Ok in 0.7.x, error in 0.8.0<br>enum YourEnum : inline int<br>TEST
int x = YourEnum.TEST; // Valid due to inline
Implicit conversion to ordinal when used as index¶<br>Enums will now implicitly convert to ordinals when used as index:<br>enum YourEnum8<br>HELLO,<br>WORLD
fn void test()<br>int[2] x;<br>x[YourEnum8.WORLD] = 123; // Same as x[1] = 123
.nameof has become .description¶<br>enum Foo<br>TESTING,<br>THE,<br>NEW,<br>DESCRIPTION
// 0.7.11<br>String s = TESTING.nameof; // "TESTING"
// 0.8.0<br>String s = TESTING.description; // "TESTING"
Constdef now infers through unary negations¶<br>Unary negation would previously prevent constdef inference constdef Abc<br>ABC = 4,<br>DEF = -4
Abc a = ABC; // Ok<br>Abc b = -ABC; // Ok in 0.8.0<br>Abc c = ~ABC; // Ok in 0.8.0
Operator overloading¶<br>Overloads for comparisons¶<br>@operator( is now added, so that a type which overloads both and == can participate in all comparisons.<br>@operator(!=) removed¶<br>@operator(!=) was removed as it had limited usefulness.<br>Compile time enhancements¶<br>Shadow an a = ... parameter if it's not defined¶<br>Shadowing is now allowed:<br>macro @foo(a = ...)<br>$if !$defined(a)<br>var a = 123; // Previously a shadowing error<br>$endif<br>return a * 2;
Use $eval as the name of a named parameter¶<br>foo(arg: 2);
// Possible since 0.8.0:<br>foo($eval("arg"): 2);
untypedlist as a new builtin type¶<br>During compile time, some compile time arrays get the type "untypedlist", containing a (possibly heterogenous) list of values. Previously it was possible to create it, but it wasn't possible to directly reference the type. This changes with 0.8.0:<br>// 0.7.11 - 'var' is the only possibility<br>var $foo = { 1, "hello", 3.14 };
// 0.8.0<br>untypedlist $foo2 = { 1, "hello", 3.14 };
The main use is to be able to test whether an expression is an untyped list or not. Regular variables cannot have this type, it's a compile time type only.<br>Added a tags property¶<br>An often requested functionality is getting all the tags on a type or member. This is now finally possible in 0.8.0:<br>struct Foo @tag("a", "hello") @tag("b", "test")<br>int x @tag("c", 5);
int a_global @tag("d", 3.14);
String[] $tags_of_foo = Foo::tags; // { "a", "b" }<br>String[] $tags_of_x = $reflect(Foo.x).tags; // { "c" }<br>String[] $tags_of_a_global = $reflect(a_global).tags; // { "d" }
Also note that name for retrieving and testing for tags have changed to get_tag and...