Dumb question about contracts: I was reading the docs (https://c3-lang.org/language-common/contracts/) and this jumped out
"Contracts are optional pre- and post-condition checks that the compiler may use for static analysis, runtime checks and optimization. Note that conforming C3 compilers are not obliged to use pre- and post-conditions at all.
However, violating either pre- or post-conditions is unspecified behaviour, and a compiler may optimize code as if they are always true – even if a potential bug may cause them to be violated.
In safe mode, pre- and post-conditions are checked using runtime asserts."
So I'm probably missing something, but it reads to me like you're adding checks to your code, except there's no guarantee that they will run and whether it's at compile or runtime. And sometimes instead of catching a mistake, these checks will instead silently introduce undefined behaviour into your program. Isn't that kinda bad? How are you supposed to use this stuff reliably?
(otherwise C3 seems really cool!)
The GitHub project has more details: https://github.com/c3lang/c3c
Some ways C3 differs from C:
- No mandatory header files
- New semantic macro system
- Module-based namespacing
- Slices
- Operator overloading
- Compile-time reflection
- Enhanced compile-time execution
- Generics via generic modules
- "Result"-based zero-overhead error handling
- Defer
- Value methods
- Associated enum data
- No preprocessor
- Less undefined behavior, with added runtime checks in "safe" mode
- Limited operator overloading (to enable userland dynamic arrays)
- Optional pre- and post-conditions
They named Result (or Expected) Optional? No, no, "optional" means "T or empty." Not "T or E."
https://c3-lang.org/language-fundamentals/functions/#functio...
Tsoding did a bunch of livestreams using C3. Over 30h worth if anyone’s interested.
https://youtube.com/playlist?list=PLpM-Dvs8t0VYwdrsI_O-7wpo-...
I haven’t tried C3 myself, but I happened to interact a lot with Christopher Lerno, Ginger Bill and multiple Zig maintainers before. Was great to learn that C3, Odin and Zig weren’t competing with each other but instead learn from each other and discuss various trade-offs they made when designing their languages. Generally was a very pleasant experience to learn from them on how and why they implemented building differently or what itch they were scratching when choosing or refusing to implement certain features.
Just browsed the doc to get the answers to two burning questions, which I will dump here in case it saves some time to others:
- uses LLVM (so: as portable as LLVM)
- sadly, does not support tagged enums
Apart from that it adds a few very desirable things, such as introspection and macros.I wonder, at which point it is worth it to make a language? I personally implemented generics, slices and error propagation in C… that takes some work, but doable. Obviously, C stdlib goes to the trash bin, but there is not much value in it anyway. Not much code, and very obsolete.
Meanwhile, a compiler is an enormously complicated story. I personally never ever want to write a compiler, cause I already had more fun than I ever wanted working with distributed systems. While idiomatic C was not the way forward, my choice was a C dialect and Go for higher-level things.
How can we estimate these things? Or let's have fun, yolo?
I was expecting something very bare-bones, but was pleasantly surprised to see a rich list of new and useful features. And maybe it's not the deepest of things to highlight, but what really made me giggle is how C3's analogue to exceptions are called Excuses.
This is what a website for a programming language should look like.
I've enjoyed using the C3 language to make some simple games [0] and found it really easy to pick up. The only thing that I got hung up on at first was the temporary memory arenas which I didn't know existed and ultimately really liked.
I see from `test/test_suite/compile_time_introspection/paramsof.c3t` that there is a way to get names & types of function parameters [1]. The language also seems to support default values { e.g. `int foo(int a, int b = 2) {...}` } and even call with keyword arguments/named parameters [2], but I couldn't find any `defaultof` or similar thing in the code. Does anyone know if this is just an oversight / temporary omission?
[1] https://github.com/c3lang/c3c/blob/master/test/test_suite/co...
Google is making a similar attempt with C++ called Carbon Language: https://github.com/carbon-language/carbon-lang
It's funny seeing the problems with C Niklaus Wirth pointed out originally still trying to be solved. He solved them with pascal and its OO successors, though for some reason it's not cool still.
I suppose it has less of the ability to blow your foot off and so isn't a very dangerous way to code, therefore not cool. If any of you younger folk haven't looked at it, I'd suggest having a look, there is Delphi - a cross platform dev environment that addresses all these problems and compiles in less than a second, or there's the free, open source alternative Lazarus. They also compile to mobile platforms and even the raspberry pi (Lazarus) or Arduino.
If you like contracts then ADA is the way to go, but I haven't used this for many years, so not sure what is the state of the compilers.
This looks like Zig. What problems does this solve that Zig doesn't? Potato - potaato?
Does anyone who has actually used C3, Odin, and Zig talk about how to think of these three?
Previous discussions:
July 2025 (159 comments, 143 points): https://news.ycombinator.com/item?id=44532527
Was an interesting ready but sad to see that there is nothing special for matching or restructuring tagged unions (beyond the special cased optional type). That's one of the things from Rust I miss the most in my day to day work with C/C++.
This seems pretty neat! Still holding out for a language with Go's runtime and compilation and performance characteristics, but language syntax and semantics like Gleam... Maybe one day
This is neat and I wish C3 well. But using Nim has shown me the light on maybe the most important innovation I've seen in a native-compiled systems language: Everything, even heap-allocated data, having value semantics by default.
In Nim, strings and seqs exist on the heap, but are managed by simple value-semantic wrappers on the stack, where the pointer's lifetime is easy to statically analyze. Moves and destroys can be automatic by default. All string ops return string, there are no special derivative types. Seq ops return seq, there are no special derivative types. Do you pay the price of the occasional copy? Yes. But there are opt-in trapdoors to allocate RC- or manually-managed strings and seqs. Otherwise, the default mode of interacting with heap data is an absolute breeze.
For the life of me, I don't know why other languages haven't leaned harder into such a transformative feature.
Its successor will be C4!
The front page reads like a D language checklist :-)
I see 'fn void main()'. There's probably a good reasson but why the 'fn'? It doesn't really add anything because 'void main()' already communicates it's a function.
The main draw of C (to me) is it's terseness and it's avoidance of 'filler' syntax words.
I admit I didn't (yet) look much further into it, but this first thing jumped out to me and slightly diminished my desire to look further into C3...
I am not a C programmer but I always find these low level languages intriguing.
I am wondering though: when does one pick C3 for a task/problem?
Anyone use zig vs C3? Seems like a lot of overlap, curious about people’s experiences with both
My university had us program in c++ with resolve. Which looks very similar to the contract stuff here.
I think the switch statement design is a foot gun: defaults to fall-through when empty and break when there is a body.
https://c3-lang.org/language-overview/examples/#enum-and-swi...
I keep thinking about perhaps LLMs would make writing code in these lower-level-but-far-better-performing languages in vogue. Why have claude generate a python service when you could write a rust or C3 service with compiler doing a lot of heavy lifting around memory bugs?
Does c3 use llvm?
Windows is a horse that is becoming less and less rideable. Be great to get this to build on ReactOS as just a hobby or side effort.
Why have features but then the compiler doesn’t make programs that enforce it…
I’m seeing a lot of this in the docs:
“However, just like for const the compiler might not detect whether the annotation is correct or not! This program might compile, but will behave strangely:”
Looks interesting, but operator overloading is an anti-pattern. Leading with that is like leading with "full support for null pointers."
Interesting! If today I wanted to start a project in a C-like language, I'd have chosen Zig. Would you tell a rough overview of how C3 differs from something like Zig?
I like the idea of strict improvements to C without taking anything away or making any controversial (as far as language design goes) choices.
One thing I am wondering is why new low level languages remove goto (Zig, C3, Nim). I think it's sometimes the cleanest, most readable and most maintainable solution. I get that's rare but especially when you are expressing low level algorithm operating on arrays/blocks/bit streams it can be useful. It's not that you can't express it with "structured" constructs but sometimes it's just not the best way. I get removing backwards goto when you provide alternative constructs for state machines but forward one is useful in other contexts.
Is it a purely ideological choice or does it make the compiler simpler/faster?
It seems great to have something that is C but cleaned up, although clay had all that with templates and move semantics.
I think leaving out move semantics and destructors is inexcusable at this point. It is not only fundamental, but doesn't affect things like standard libraries, runtimes, or ABIs.
" the C-like for programmers who like C."
Sounds intriguing. But then, the first thing I noticed in their example is a double-colon scope operator.
I understand that it's part of the culture (and Rust, C#, and many other languages), but I find the syntax itself ugly.
I dunno. Maybe I have the visual equivalent of misophonia, in addition to the auditory version, but :: and x << y << z << whatever and things like that just grate.
I like C. But I abhor C++ with a passion, partly because of what, to me, is jarring syntax. A lot of languages have subsequently adopted this sort of syntax, but it really didn't have that much thought put into it at the beginning, other than that Stroustrup went out of his way to use different symbols for different kinds of hierarchies, because some people were confused.
Source: https://medium.com/@alexander.michaud/the-double-colon-opera...
Think about that. The designer of a language that is practically focused on polymorphism went out of his way to _not_ overload the '.' operator for two things that are about as close semantically as things ever get (hierarchical relationships), simply because some of his customers found that overloading to be confusing. (And yet, '<<' is used for completely disparate things in the same language, but, of course, apparently, that is not at all confusing.)
I saw in another comment here just now that one of the differentiators between zig and C3 is that C3 allows operator overloading.
Honestly, that's in C3's favor (in my book), so why don't they start by overloading '.' and get rid of '::' ?
We have solved the better C issue, but nobody seems keen on solving the better compiler issue
Why do we still have to recompile the whole program everytime we make a change, the only project i am aware of who wants to tackle this is Zig with binary patching, and that's imo where we should focus our effort on..
C3 does look interesting tho, the idea of ABI compatibility with C is pretty ingenious, you get to tap into C's ecosystem for free
not being able to do alias i32 = int; was the biggest turn off for me
c3 is as easy as 1,2,3
[dead]
[flagged]
Honestly if your programming language does not compile to wasm I don't care for it. That's my new rule.
If I had a dollar for every C successor...
I've been following C3 for sometime now, and I really appreciate the discipline in the design philosophy here.
Neither does it force a new memory model on you, nor does it try to be C++. The killer feature for me is the full ABI compatibility. The fact that I no longer have to write bindings and can just mix C3 files into my existing C build system reduces the friction to near zero.
Kudos to the maintainer for sticking to the evolution, not revolution vision. If you are looking for a weekend language to learn that doesn't require resetting your brain but feels more modern than C99, I highly recommend giving this a shot. Great work by the team.