14 ms·
Show HN: The C3 programming language (C alternative language)
Get it from here: https://github.com/c3lang/c3c https://github.com/c3lang/c3c
In 2019, while contributing to the C2 language, I started up "C3" as a pet project while waiting for pull requests to be approved...
Now it's 6 years later and C3 well on its way to 1.0, having released 0.7.0 last week.
Unlike other C alternatives, C3 tries to evolve C – but without concern to backwards compatibility to the latter.
What it adds to C is among other things:
- Module system
- Semantic macros and compile time introspection
- Lightweight generic modules
- Zero overhead errors
- Build-in slices and SIMD types
- Gradual contracts
- Built-in checks in debug mode
You can find more details on the site: https://c3-lang.org https://c3-lang.org
It might be interesting to look at the examples: https://c3-lang.org/language-overview/examples/ https://c3-lang.org/language-overview/examples/ so see how the language looks for some simple examples.
Some other links that might be interesting follows:
I've posted about C3 on HN before, notably
- https://news.ycombinator.com/item?id=24108980 https://news.ycombinator.com/item?id=24108980
- https://news.ycombinator.com/item?id=27876570 https://news.ycombinator.com/item?id=27876570
- https://news.ycombinator.com/item?id=32005678 https://news.ycombinator.com/item?id=32005678
Here are some interviews on C3:
- https://www.youtube.com/watch?v=UC8VDRJqXfc https://www.youtube.com/watch?v=UC8VDRJqXfc
- https://www.youtube.com/watch?v=9rS8MVZH-vA https://www.youtube.com/watch?v=9rS8MVZH-vA
Here is a series doing various tasks in C3:
- https://ebn.codeberg.page/programming/c3/c3-file-io/ https://ebn.codeberg.page/programming/c3/c3-file-io/
Some projects:
- Gameboy emulator https://github.com/OdnetninI/Gameboy-Emulator/ https://github.com/OdnetninI/Gameboy-Emulator/
- RISCV Bare metal Hello World: https://www.youtube.com/watch?v=0iAJxx6Ok4E https://www.youtube.com/watch?v=0iAJxx6Ok4E
- "Depths of Daemonheim" roguelike https://github.com/TechnicalFowl/7DRL-2025 https://github.com/TechnicalFowl/7DRL-2025
- unclad5968 2y agoI have used this language for a few things (csv parsing and some simple personal cli tools). Other than the normal pre-1.0 issues it's great. I wish it had a tagged union type, but it looks like that's planned based on the github issue tracker. It is a pretty big improvement on C without changing the ABI. Maybe not the improvements I would make if I was smart enough to make a compiler, but better than doing C which I also enjoy despite it's warts.
- SwiftyBug 2y agoMaking compilers are not that hard. Sure, it grows in complexity as you make it more feature-complete. But writing compilers is actually a lot of fun. If you're interested in compilers you should definitely try making a simple one. This book is free and a great starting point: https://craftinginterpreters.com/ https://craftinginterpreters.com/. I'm not associates with the book author in any way, I just found incredible value in it.
- lerno 2y agoThe hard thing is staying with the project. Lots of interesting C-like projects have died over time, such as https://www.kitlang.org https://www.kitlang.org
- dingdingdang 2y agoDoes C3's compiler utilise the highly optimized C compilers like clang and gcc similar to Vlang and Nim?
- KerrAvon 2y agoit uses LLVM, see the bottom of TFA
- sparky4pro 2y agoIt uses llvm.
- tombhowl 2y ago[dead]
- unquietwiki 2y agoProgramming language dev is quite common. I've been cataloging various languages on r/altprog on Reddit. This particular one seems to have influences from several other languages (quite a few use "fn" for function declaration, plus there's a module system).
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- dooglius 2y agoHow does this compare to Zig or Odin, which have the same goals of improving upon C and have gotten occasional publicity here on HN?
- deleted 2y ago[deleted]
- johnisgood 2y agoIt is answered here: https://c3-lang.org/faq/compare-languages/ https://c3-lang.org/faq/compare-languages/
- dkersten 2y agoI feel like its missing a point for "In C3 but not in Jai": you can actually download and use C3...
- lerno 2y agoWell, it's not that difficult to get into the Jai beta if you are building something with Jai I think? I seem to recall that Jon just asked beta testers that they actually have a project that they will use it for?
- dkersten 2y agoHow can you build something in Jai before you have access to Jai? I heard he only gives access to people who more out less guarantee they will use it relatively heavily, but how can I know of I will before I can scarily try it? Basically I heard he only gives access if he thinks you will use it — not just so you can try it. That might work fine for people with enough time on their hands that they can say “I’ll do this full project in it, regardless of how it goes”, but I prefer to be able to tinker first to see if I find it suitable. For example, I’ve had projects where I though “ok I’m going to do this in Rust|Zig” and after trying for a few days realising that it’s not the route I want to take. In any case, anyone can just download C3 and try it. You can’t just download Jai to try it. So my statement is still true.
- johnisgood 2y agoAre there any examples of using a C library (binding, FFI) in C3? A quick search came up empty.
- sparky4pro 2y agoHere you go: https://ebn.codeberg.page/programming/c3/c3-opengl/ https://ebn.codeberg.page/programming/c3/c3-opengl/ This one is for OpenGL.
- lerno 2y agoDid you see this? https://c3-lang.org/language-common/cinterop/ https://c3-lang.org/language-common/cinterop/
- johnisgood 2y agoOops, I missed that, thank you! Seems straightforward. I will give it a spin later. :)
- Sohcahtoa82 2y agotbh I think one of the things I really liked reading through examples was the change in the switch/case behavior. I always thought implicitly falling into the next case was an awful design, and that a break is the more logical implicit behavior except in the case (no pun intended) of stacked empty case statements. I do all my coding in Python, but if I ever find myself needing to reach for C again, I'll certainly consider this. EDIT: Though is there a reason why "fn" is needed? I would think the AST builder would still be able to identify the beginning of a function definition without it, and as a programmer, I can identify a function definition easily.
- mjburgess 2y agoThings like that make grepping easier. And redundancy of syntax makes reading-without-mistake faster. The more you put on the page the lower the cognitive load, the more spare it has in it, the easier it is to search for increasingly refined contexts of use.
- alcover 2y agoAgreed. It's tempting to make the tersest lang you can but in the end what matters is ease of reading. For ex. parens-less calls (myfunc 42 "hello") are elegant but don't stand out and - for me - take more time to identify. Also `fun foo(i:int)` is easier on the parser than C-style `void foo(int i)`
- johnisgood 2y agoI prefer lack of "fun" and "fn", to me it is easier to parse C-style. :( This is one of the things (albeit minor) that put me off of C alternatives, I like to keep things as simple as possible, but I understand it has "macro" as well, so might as well have "fn", for the reasons already mentioned. That said, I will still try C3.
- lerno 2y agoAlso, `fn` is used to make type inference for lambdas syntactically simple. But I would lie if I said I haven’t been considering removing `fn` many times. But there are good reasons for keeping it, despite the break with C.
- sfpotter 2y agoOne thing I just can't understand is proactively using the :: syntax. It's sooo ugly with so much unnecessary line noise. Just use a single period! I think one of the best decisions D made was to get of -> and :: and just use . for everything.
- lerno 2y ago`::` simplifies the module vs identifier resolution. In C3 there is something called "path shortening", allowing you to use `foo::bar()` in place of something like `std::baz::foo::bar()`. To do something similar with `.` is problematic, because you don't know where the path ends. Is `foo.baz.bar()` referring to `foo::baz::bar()` or `foo::baz.bar()` or `foo.baz.bar()`?
- WhitneyLand 2y agoSure, but in practice I believe most developers would find it intuitive to just type . everywhere. It feels more lightweight and consistent, and collisions aren’t super common once you adopt some conventions. It’s a tradeoff for sure, but this preference comes from having lived in both worlds.
- PartiallyTyped 2y agoN=1; I find :: a lot more obvious.
- steveklabnik 2y agoI’ve lived in both and I prefer ::.
- gpderetta 2y agoI prefer a world where there is no distinction between modules (or namespaces) and object, so '.' it is. (and I'm almost exclusively a C++ programmer).
- lelanthran 2y ago
- alcover 2y agoHello, your doc about const says "The const qualifier is only retained for actual constant variables". Then how do you express read-only pointers ? Like C `const int* ptr`
- lerno 2y agoIf you pass them as parameters, then there are in/out/inout annotations to limit usage. But other than that, there isn't anything.
- dkersten 2y agoOh. This actually looks like something I could see myself using, maybe. I thought I'd hate it, but after checking out the examples, this is pretty nice. There are some syntax choices that aren't ones I'd have made (eg I prefer `ident: Type` and types being uppercase, I don't like `fn type identifier ()` for functions etc), but coming from C, I can see how and why it ended up like it did, and overall this looks really good. Great work!
- Surac 2y agoas much as i like a better 'C' language, it is hard to use them. so many things have been done in C and you find everything in the net you would ever like to use. Using a better 'C' places you on that strange island where no one hears you cry. Using C3 in a company places you in a place where only you can understand the code.
- lerno 2y agoYes, this is a very real problem that I've also written about: https://c3.handmade.network/blog/p/8486-the_case_against_a_c_alternative https://c3.handmade.network/blog/p/8486-the_case_against_a_c...
- fuzztester 2y agoAny other C alternative or C-like languages that people here are using more than experimentally? Asking because my above question and this current post about C3 are related to this recent post by me, which had a good number of comments: Ask HN: What less-popular systems programming language are you using? https://news.ycombinator.com/item?id=43223162 https://news.ycombinator.com/item?id=43223162
- lerno 2y agoOther than C3, there is Jai, Odin, Zig and Hare which are the ones that have any traction right now that I know of. Many interesting projects have been started but ultimately later abandoned. Going to C++ competitors there is obviously Rust, but also Nim, Crystal, Beef and a lot of others. (And Jai is a C++ competitor too)
- fuzztester 2y agothanks.
- tialaramex 2y agoNotably all of these you mentioned aren't finished. C3 is 0.7, Jai is an "internal beta", Odin is working through a series of "dev" builds, Zig is 0.14, and Hare 0.24.2 This is maybe more striking when comparing against C which was already very old and battle tested in 1989 when it was standardized. If you pick any of these languages you're accepting an unknowable amount of churn. It better be worth it.
- lerno 2y agoYes: https://c3.handmade.network/blog/p/8486-the_case_against_a_c_alternative https://c3.handmade.network/blog/p/8486-the_case_against_a_c...
- fuzztester 2y ago>This is maybe more striking when comparing against C which was already very old and battle tested in 1989 when it was standardized. If you pick any of these languages you're accepting an unknowable amount of churn. C has plenty of issues too, even though it is very old, battle tested and standardized. (How about all the UB in C, for example?) That is why people are looking for C alternatives in the first place. >It better be worth it. It better be worth it for C too (and for C3; pun unintended but evaluated).
- tomdawgnigger 2y ago[dead]
- xormapmap 2y agoSo many of the so-called "C alternatives" end up doing way too much. I don't need algebraic data types or classes or an integrated build system or a package manager. What I would like to see is a language that is essentially just C with the major design flaws fixed. Remove the implicit casting and obscure integer promotions. Make spiral rule hold everywhere instead of being able to put const at the beginning of the declaration. Make `sizeof()` return a signed type. Don't allow mixed signed/unsigned arithmetic. Make variables/functions private by default i.e. add `public` to make public instead of `static` to make private. Keep the preprocessor and for the love of god make it easy to invoke the compiler/linker directly so I can write my own Makefile.
- baranul 2y agoArguably, what you describe, is closer to what C2 was/is[1]. By the way, C2 is still alive, for those that care to look. C3 (link[2]) is a fork of/inspired by C2, which appears to have incorporated a lot of Odin and Jai "flavoring". In the case of both C3 and Odin, it can be argued that part of their popularity is that Jai isn't publicly released. Consequently, they seem to pull in a lot of the crowd, that would be attracted to Jai. Another aspect of this, is the more C3 promotes itself (whether intentional or not), the more likely C2 will get faded out. Many will likely think C3 is the next iteration of C2 or simply know the name more, because pushed on HN and other social media. [1] https://github.com/c2lang/c2compiler https://github.com/c2lang/c2compiler [2] https://github.com/c3lang/c3c https://github.com/c3lang/c3c
- lerno 2y agoIsn’t it a somewhat unfair characterization that ”C3 promotes itself more” and ”is pushed on HN and other social media” and that because of this C2 for some reason experiences harm? C2 is over 11 years now. C3’s recent breakthrough this last half year is unlikely to have had much impact on its ability to grow the last 10 years.
- baranul 2y agoThis thread literally meets the definition of self-promotion. So no, don't think the characterization is unfair. If your programming language had a different name, then I would agree, but it doesn't. Many will assume that C3 is the next iteration of C2 and that it's outdated, despite the fact that C2 is still in development.
- micklemeal 2y agoRecently gave this language a spin with raylib and libtmx for loading tiled maps. Out of C3, Zig, and Odin, I've had the least trouble integrating C libraries with C3 (rolled my own bindings for libtmx). Overall a big fan of the language and am hoping it gets recognition on the level of the other languages mentioned here.
- owlstuffing 2y agoOverall, this is one of the better C killers I’ve seen. But keeping macros while ditching conditional compilation? That seems completely backward to me. Oh well.
- lerno 2y agoWhat kind of conditional compilation are you missing?
- spc476 2y agoFor adapting code to different versions of libraries for one thing: #if defined(__SunOS) presult = getprotobyname_r(proto,&result,tmp,sizeof(tmp)); if (presult == NULL) return luaL_error(L,"protocol: %s",strerror(errno)); #elif defined(__linux__) if (getprotobyname_r(proto,&result,tmp,sizeof(tmp),&presult) != 0) return luaL_error(L,"protocol: %s",strerror(errno)); #else presult = getprotobyname(proto); if (presult == NULL) return luaL_error(L,"protocol: %s",strerror(errno)); result = *presult; #endif The sometimes annoyingly small differences between platforms.
- lerno 2y agoOh, I think you missed something then: There is both `$if` and `$switch` compile time statements for this: https://c3-lang.org/generic-programming/compiletime/#if-and-switch https://c3-lang.org/generic-programming/compiletime/#if-and-... At the top level and `@if` attribute is used to achieve the same thing: https://c3-lang.org/language-common/attributes/#if https://c3-lang.org/language-common/attributes/#if
- owlstuffing 2y agoAh. The top-level lang description claims “No preprocessor”, but my definition of that word doesn’t appear to be the same as yours :/
- 2y ago
- johnisgood 2y ago@lerno, how do you feel about contributions to the standard library? For example, I might add BLAKE2 if it is not already implemented. Also I just checked the source code of hash map. What if I want to use a different hashing algorithm for "rehash"? There is no one true implementation of a hash table either, for example, so I am not sure what to do with that. I want a thread-safe hash table, I wonder if it would ever make it into the standard library.
- lerno 2y agoBlake2 and other hashes are most welcome. As for HashMap you are completely correct: there are many different types of maps that are needed. Concurrent maps, insertion ordered maps etc. And even variations of the small things: are keys copied or not! I talked about this on a stream recently, how the standard library is in need of a lot of additional Maps, Sets and Lists. So if you’re interested in contributing then you’re very welcome to do so.
- johnisgood 2y ago> And even variations of the small things: are keys copied or not! Yeah, or if duplicates are allowed or not, initial size, load factor, and so forth.
- accelbred 2y agoDoes it allow you to make functions weak? Can you do something like gcc's constructor attribute?
- lerno 2y agoYes both are implemented as attributes `@weak` and `@init` respectively.
- stefantalpalaru 2y ago[dead]
- djmips 2y agoDoes it have native fixed point types?
- lerno 2y agoNo, there is an incomplete proposal for it here though: https://github.com/c3lang/c3c/issues/1451 https://github.com/c3lang/c3c/issues/1451 What would you like to use it for?
- djmips 2y agoI find it useful in lower powered systems without floating point hardware. It may be a feature whose time has passed but it still seems like there's both a case for it and probably an elegant design waiting. Imagine using it on a 6809 system for example. :)
- lerno 2y agoYou could still do it as a userland feature and implement add/sub/mult/div as methods on the type.
- djmips 2y agoThat never works as well as having it built into the compiler.
- Joshringuk 2y agoYou can define your own "built-ins" types and functions(!) so that should make it indistinguishable. You can also extend the standard Library from inside your own project, modules are open for extension
- lerno 2y agoWell, you're free to revive this issue: https://github.com/c3lang/c3c/issues/1451 https://github.com/c3lang/c3c/issues/1451. I'd need a more solid proposal.
- moktonar 2y agoWhy the “fn” token?
- lerno 2y agoI tried to answer that here: https://c3.handmade.network/blog/p/8886-why_does_c3_use_%2527fn%2527 https://c3.handmade.network/blog/p/8886-why_does_c3_use_%252...
- CyberDildonics 2y agoI think any system language going forward really needs three things: 1. Generics / templates 2. Destructors 3. Ownership It is unfortunate that this only has the first one. There was a language called clay that had all three and kept easy integration with the C ABI, but it seems like that design has been lost.
- lerno 2y agoDestructors and Ownership implies RAII and all the design and architecture that are assumed with such things. This is far from C semantics, and so out of scope for C3. Any RAII language will be considered a C++ competitor, not a C alternative. None of Zig, Odin, C3 or Hare has RAII.
- CyberDildonics 2y agoThe problem is that C semantics leads to C problems that the world has dealt with for decades. It sounds like you are leaving tried and tested simple advancements in programming on the table just to avoid a superficial comparison. Even then what C++ people want from a competitor is simplicity. Not to give up the essentials but to keep the crucial aspects that they can never give up and are the reason they put up with all of the complexity of C++.
- lerno 2y agoPersonally I think it is reasonable that a C alternative is an alternative to C, and not a C++ alternative. C3 uses a temp allocator that removes a large number of cases where C++ would need RAII to manage memory. Did you try C3?
- CyberDildonics 2y agoDoes it just deallocate at the end of a scope? Why go halfway? It's obviously valuable and destructors are not complicated. Destructors can also close files, sockets, deallocate buffers from the GPU, etc. I think when people want C semantics they will just use C in general, but if there is something that solves these extreme pain points in a simple way it might be enough to get someone to switch.
- TZubiri 2y agoWe are running out of names for C successor languages, yet nobody seems to have taken YACS
- deagle50 2y agoThe language looks great but I can't get over the "type first" declaration syntax.
- lerno 2y agoNot a C fan then ;)
- SleepyMyroslav 2y agoA low effort question on what's C3 take on pointer provenance. Does C3 have any own take on it? Are you with C or with your implementation detail (LLVM) ? Also if you have 'tourist guide' for gamedev people please share links or short tips. I have no idea about C replacements myself because gamedev that I know is not using C. ps somehow in my part of the internet your blog is not accessible with cloudflare saying access denied. Do you have any copy/backup of it elsewhere?
- Joshringuk 2y ago@lerno is a ganedev himself so should be able to answer your question there Some links https://c3-lang.org/getting-started/ https://c3-lang.org/getting-started/ https://c3-lang.org/getting-started/design-goals/ https://c3-lang.org/getting-started/design-goals/ https://c3-lang.org/faq/compare-languages/ https://c3-lang.org/faq/compare-languages/ The blog is on the internet archive https://web.archive.org/web/20250330145704/https://c3.handmade.network/blog/p/9010-c3_0.7_released_-_one_step_closer_to_1.0#30446 https://web.archive.org/web/20250330145704/https://c3.handma...
- lerno 2y agoI don't have any particularly strong stance on provenance. But I've yet to see a strong argument for it in C. There is not much of a guide I'm afraid. I translated some of the raylib examples to C3: https://github.com/c3lang/c3c/tree/master/resources/examples/raylib https://github.com/c3lang/c3c/tree/master/resources/examples... But those are straight up conversions of the original C code. I think any C tutorial on gamedev would work fine to follow in C3, and then one can leverage features of C3 as desired.
- SleepyMyroslav 2y agoJudging from 'comparing pointers of different provenance' can produce 'any result' ( here https://c3-lang.org/language-rules/undefined-behaviour/#list-of-implementation-dependent-behaviours https://c3-lang.org/language-rules/undefined-behaviour/#list... ) everyone has to deal with it. More low effort questions. Question about optional debug traps: are they available in optimized builds? Are any LLVM sanitizers available? It usually means language needs to have APIs to mark up your own allocators/containers/etc. Does language help parallel/concurrent programs to be more readable?