[HN Gopher] Show HN: The C3 programming language (C alternative ...
___________________________________________________________________
Show HN: The C3 programming language (C alternative language)
Get it from here: 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 It might be
interesting to look at the 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=27876570 -
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=9rS8MVZH-vA Here is a series doing
various tasks in C3: -
https://ebn.codeberg.page/programming/c3/c3-file-io/ Some
projects: - Gameboy emulator https://github.com/OdnetninI/Gameboy-
Emulator/ - RISCV Bare metal Hello World:
https://www.youtube.com/watch?v=0iAJxx6Ok4E - "Depths of
Daemonheim" roguelike https://github.com/TechnicalFowl/7DRL-2025
Author : lerno
Score : 88 points
Date : 2025-04-03 13:55 UTC (9 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| unclad5968 wrote:
| I 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.
| dingdingdang wrote:
| Does C3's compiler utilise the highly optimized C compilers like
| clang and gcc similar to Vlang and Nim?
| KerrAvon wrote:
| it uses LLVM, see the bottom of TFA
| sparky4pro wrote:
| It uses llvm.
| dooglius wrote:
| How does this compare to Zig or Odin, which have the same goals
| of improving upon C and have gotten occasional publicity here on
| HN?
| johnisgood wrote:
| It is answered here: https://c3-lang.org/faq/compare-languages/
| dkersten wrote:
| I feel like its missing a point for "In C3 but not in Jai":
| you can actually download and use C3...
| pixelpoet wrote:
| For one thing, C3 thankfully understands that there are more
| mathemathical types people are interested in than just ints and
| reals, for example vectors: https://c3-lang.org/language-
| common/vectors/
|
| Zig has SIMD vectors, but I frequently need 3D vectors, and
| refuse to use things like vec3_add(vec3_mul(a, 2), b) etc since
| I mainly develop 3D graphics software.
| lerno wrote:
| As the author, let me add something beyond the comparison. Zig
| and Odin are very different languages, Odin is - as its slogan
| goes - "for the Joy of Programming". Zig on the other hand
| doesn't feel that this is a goal. From what I can tell Zig fans
| like to wrestle with the features of Zig to figure out how to
| fit their solutions within the constraints of the language. A
| mental challenge, similar to that of fighting the borrow
| checker in Rust. People who "figured out" Zig tend to be
| fiercely loyal to the language in a similar way as Rust
| evangelists to Rust.
|
| C3 has a lot in common with Odin, but very little in common
| with Zig.
|
| C3 has a slightly different feature set than Odin (e.g. more
| compile time execution, has methods, contracts, but doesn't
| have Odin's matrix programming and more extensive runtime
| reflection), but the goals aligns strongly with Odin's.
|
| If you prefer C syntax and semantics you might like C3 better,
| but Odin is a fine language too.
| judofyr wrote:
| > People who "figured out" Zig tend to be fiercely loyal to
| the language in a similar way as Rust evangelists to Rust.
|
| This is very much _not_ productive and you're now part of
| spreding this narrative. There's plenty of people out there
| who has <<figured out>> and appreciate both Zig and Rust
| without becoming attached to it.
|
| I'm interested in communities which looks towards other
| languages for inspiration and admiration, not judgements and
| alienation.
| unclad5968 wrote:
| So which language do you use then? I've never seen a
| language that doesn't have bad things to say about other
| languages. Zig bdfl himself accused vlang of committing
| fraud a while back.
|
| Every language designer takes things they like about some
| languages and leaves things they don't like.
| wk_end wrote:
| > Zig bdfl himself accused vlang of committing fraud a
| while back.
|
| I think there's a difference between a critical
| generalization of a community and the mindset behind it
| and how that relates to the language (without weighing in
| on how legitimate that criticism is), and a direct
| accusation that one individual did a specific bad thing.
| judofyr wrote:
| > I've never seen a language that doesn't have bad things
| to say about other languages.
|
| That's why I said "communities" and not "languages".
| Every programming language has a wide set of people who
| use it. You can always find some people who constantly
| say bad things about other languages. You can _also_ find
| people who are interested in the different trade offs of
| the language. I use languages which are technically
| interesting, and then I engage with the parts of the
| community which are interested in finding the best
| solutions to _actual_ problems.
|
| And guess what? Most of the Zig and Rust community are,
| in my experience, way more focused on solving real
| problems than to push their language at all cost. Both
| /r/rust and /r/zig will often recommend different
| languages. I mean, this was the most upvoted comment
| around how to convince someone's boss to use Rust over
| Python: https://old.reddit.com/r/rust/comments/14a7vgo/ho
| w_to_convin....
| unclad5968 wrote:
| > than to push their language at all cost
|
| Nobody said they do that
| lerno wrote:
| For what it's worth, I found the Zig community on the
| biggest Zig discord very nice and welcoming. But _that
| said_ , there is a lot of _" you have to understand Zig"_
| sentiment. Also, there is a lot of "I discovered Zig and
| it's finally showing me how to program" echoed as well.
|
| I don't find this an unfair judgment but rather an
| observation.
|
| I think this naturally arises from the language claiming to
| be "a programming language designed for robustness,
| optimality, and clarity" (See for instance
| https://www.recurse.com/events/localhost-andrew-kelley)
|
| If you feel that this is an optimal programming language
| that gives more robustness and clarity than other
| languages, then it's natural to be preachy about it.
|
| This is similar to Rust being sold as _safe_ language,
| where similarly the proponents of Rust feel that the
| advantages of Rust need to be spread.
|
| As a contrast, Odin focuses on "joy of programming" as its
| main goal, and the author does not make any claims of the
| language having killer features to choose it over something
| else.
|
| However, it seems to be successful in that new users tend
| to remark how pleasant and fun it is to program in the
| language.
| lerno wrote:
| Just to be clear, I don't mean the description of Zig to put
| down the language or the community. It's the best I can do to
| describe the difference between Zig on one hand and Odin/C3
| on the other.
|
| A more concrete example that might explain it better is
| looking at Advent of Code solutions.
|
| One thing that struck me was that doing typical tasks for
| parsing would be 2-3 functions stringed together in a smart
| way in the Zig solutions, whereas in Odin and C3 it was
| achieved by having a single standard library function that
| did these steps.
|
| From what I understand, there is a pushback against creating
| convenience functions in the Zig standard library, if the
| same thing can be achieved by stacking together a few
| functions.
|
| My understanding is that doing these smart things with the
| Zig library with the existing functionality of considered a
| cool way to leverage existing code.
|
| In C3, and I feel Odin as well, the lack of such a
| convenience function would be considered an omission to
| patch, and that having to stack things together should be
| reserved for specialized solutions, rather than having to
| stack things together for everyday tasks.
|
| Thus in C3 and Odin, it is okay to trade _detailed
| explicitness for convenience_ , whereas this is a no-no in
| Zig.
|
| But what this means is that Zig users tend to celebrate and
| focus on smart and clever code, whereas this is a complete
| non-goal in C3 and Odin.
|
| I could probably have formulated this better before.
| fuhsnn wrote:
| Zig and Odin compiler may implicitly pass variables by
| references[1][2], creating hidden aliasing, that's one thing
| unacceptable for me coming from C, I haven't read about C3
| doing this, hopefully it doesn't and not planned in the future.
|
| [1] https://www.1a-insec.net/blog/25-zig-reference-semantics/
| [2] https://github.com/odin-lang/Odin/issues/2971
| lerno wrote:
| C3 follows the C ABI, so no it doesn't do it and it's not
| planned.
| johnisgood wrote:
| Are there any examples of using a C library (binding, FFI) in C3?
| A quick search came up empty.
| sparky4pro wrote:
| Here you go:
| https://ebn.codeberg.page/programming/c3/c3-opengl/ This one is
| for OpenGL.
| lerno wrote:
| Did you see this? https://c3-lang.org/language-common/cinterop/
| johnisgood wrote:
| Oops, I missed that, thank you! Seems straightforward. I will
| give it a spin later. :)
| Sohcahtoa82 wrote:
| tbh 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 wrote:
| Things 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 wrote:
| Agreed. 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)`
| lerno wrote:
| I wrote a short blogpost about this before, trying to answer
| the question:
| https://c3.handmade.network/blog/p/8886-why_does_c3_use_%252...
| sfpotter wrote:
| One 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 wrote:
| `::` 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 wrote:
| Sure, 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 wrote:
| N=1; I find :: a lot more obvious.
| steveklabnik wrote:
| I've lived in both and I prefer ::.
| IshKebab wrote:
| I would just explicit require pulling `foo` into scope, like
| Rust does. Though in fairness Rust also uses :: for scope
| anyway and I don't think it's as bad as sfpotter says.
| WalterBright wrote:
| > `::` simplifies the module vs identifier resolution
|
| The identifier on the right is looked up in the scope of the
| identifier on the left. If it resolves to a module, then it's
| a module. If it resolves to a function, then it's a function.
| If the left side is a pointer (not a symbol with a scope)
| then the right side resolves to a member.
|
| It also makes refactoring much easier - changing a pointer to
| a reference does not require a global search/replace of ->
| with .
| sfpotter wrote:
| This is the kind of thing I don't want to have to think about
| as a programmer. The compiler should just make it work.
| foul wrote:
| I can understand it, I just hate it. I would prefer confusing
| dots, a module builtin namespace, rebol backslashes, confusing
| slashes, _anything else_.
| melon_tusk wrote:
| I can live with "this::that", but what drives me bonkers is
| "this :: that", which is what Odin does. Other than that, Odin
| is an incredible language.
| deagle50 wrote:
| that's a constant assignment, completely different. And
| you're not going to see it 100s of times in a project.
| alcover wrote:
| Hello, 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 wrote:
| If you pass them as parameters, then there are in/out/inout
| annotations to limit usage. But other than that, there isn't
| anything.
| dkersten wrote:
| Oh. 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 wrote:
| as 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.
| fuzztester wrote:
| Any 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
| lerno wrote:
| Other 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)
| xormapmap wrote:
| So 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.
| micklemeal wrote:
| Recently 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 wrote:
| Overall, 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 wrote:
| What kind of conditional compilation are you missing?
| spc476 wrote:
| For 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.
___________________________________________________________________
(page generated 2025-04-03 23:02 UTC)