C3 0.8.0 replaces builtins, simplifies reflection, and rethinks unsigned sizes

birdculture1 pts0 comments

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&para;<br>Distinct types now defaults to be "structlike"&para;<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&para;<br>No more +/-&para;<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 ++/--&para;<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&para;<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&para;<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&para;<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&para;<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&para;<br>Overloads for comparisons&para;<br>@operator( is now added, so that a type which overloads both and == can participate in all comparisons.<br>@operator(!=) removed&para;<br>@operator(!=) was removed as it had limited usefulness.<br>Compile time enhancements&para;<br>Shadow an a = ... parameter if it's not defined&para;<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&para;<br>foo(arg: 2);

// Possible since 0.8.0:<br>foo($eval("arg"): 2);

untypedlist as a new builtin type&para;<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&para;<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...

para language changes distinct type myenum

Related Articles