[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  : 160 points
       Date   : 2025-04-03 13:55 UTC (1 days 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.
        
         | SwiftyBug wrote:
         | Making 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/. I'm not associates with the
         | book author in any way, I just found incredible value in it.
        
           | lerno wrote:
           | The hard thing is staying with the project. Lots of
           | interesting C-like projects have died over time, such as
           | https://www.kitlang.org
        
       | 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.
        
           | zem wrote:
           | interesting example of swizzling
           | 
           | ``` int[<3>] a = { 11, 22, 33 }; int[<4>] b = a.xxzx; ```
           | 
           | I assume that the `xxzx` is translated directly by the
           | compiler. not seen that in any other language though ruby can
           | fake it pretty easily via `method_missing`
        
             | lerno wrote:
             | This is not that novel. It is inspired by the similar
             | feature in the Odin language.
        
               | zem wrote:
               | ah, neat if it's becoming a standard convention of sorts.
               | i haven't used odin either.
        
               | lerno wrote:
               | It's a good language, you should try it out as well.
        
           | bsder wrote:
           | In Zig, basic operations on vectors with standard operators
           | work fine. "+", for example.                 const meta =
           | @import("std").meta;              test "vector add" {
           | const x: @Vector(4, f32) = .{ 1, -10, 20, -1 };
           | const y: @Vector(4, f32) = .{ 2, 10, 0, 1 };          const z
           | = x + y;          try expect(meta.eql(z, @Vector(4, f32){ 3,
           | 0, 20, 0 }));       }
           | 
           | Everything is element-wise, which matches what the shading
           | languages do (mostly).
           | 
           | But, yes, you won't get overloading allowing things like dot,
           | cross, or scalar products. And I do miss the swizzle
           | notation, but I don't think the language actually prevents
           | that so it might appear at some point.
        
             | lerno wrote:
             | C3 allows arbitrary extensions of any types, so things like
             | `vec1.dot(vec2)` is actually implemented as a generic
             | method macro over all vector types added by the math
             | module.
             | 
             | Given Zig's preference for closed modules, I don't expect
             | this to be on the roadmap, but rather would need to be
             | implemented as functions.
        
         | 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
        
               | baranul wrote:
               | > Zig bdfl himself accused vlang of committing fraud a
               | while back.
               | 
               | That was truly foul. On top of that, begged readers to
               | give their money to Zig. Clearly some have no limits on
               | what to say and do against other languages or to sell
               | their language.
               | 
               | That's why whatever bad things a creator or evangelist
               | says about another language, people shouldn't just
               | swallow, and instead take with a grain of salt and some
               | skepticism.
        
               | maleldil wrote:
               | > That was truly foul
               | 
               | Is it because, as the leader of a language, he shouldn't
               | be making "attacks" against other languages? Because, as
               | far as V being a fraud, he was 100% correct.
        
               | hitekker wrote:
               | The accusation is harsh, but I think Zig's BDFL had a
               | point. V-lang seems to have been poorly led for many
               | years.
               | 
               | https://news.ycombinator.com/item?id=27441848
               | 
               | https://news.ycombinator.com/item?id=39503446
               | 
               | Many links paint a picture of constant false advertising,
               | even deception.
        
             | 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.
        
               | johnisgood wrote:
               | Off-topic (maybe should ask elsewhere), but why is C3
               | using "fn", it could not be avoided?
               | 
               | Edit: Someone already asked:
               | https://news.ycombinator.com/item?id=43572190
        
               | judofyr wrote:
               | You're kinda proving my point here by using such loaded
               | terms. You've chosen the term "preachy" (a negative word)
               | to describe people who are excited about advancements in
               | programming languages (e.g. borrow checker, powerful type
               | system, comptime, alignment as a part of type system).
               | You've chosen to not mention that Rust keeps being the
               | "Most loved programming language" (according to Stack
               | Overflow); isn't this is a sign that people find it
               | _joyful_?
               | 
               | > Also, there is a lot of "I discovered Zig and it's
               | finally showing me how to program" echoed as well.
               | 
               | So, did you try Zig? How did you find it? Did it show you
               | a new way to program? Or were you already aware of this
               | way? Or do you think it's not a good way? What did you
               | find interesting? What features did you steal because
               | they were good? What do you think is overrated? These are
               | the questions I'm interested in from other programming
               | language designers!
               | 
               | > 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.
               | 
               | And that's a fair thing to say! You can say that C3 is
               | just a slightly better C and doesn't have any other
               | killer feature. I'm just not sure why you need to talk
               | negatively about other languages.
        
               | lerno wrote:
               | I tried Zig in 2017-2018 span (and as part of research
               | I've read quite a bit of Zig over the years). To me the
               | language had some details not previously tried out:
               | special operators for wrapping ops, error value based
               | error returns and pervasive NPOT types. But overall it
               | felt unnecessarily verbose with what I feel were
               | unnecessary changes to established syntax in standard
               | constructs such as "for" and "while". For this reason I
               | started to contribute to C2 instead.
               | 
               | However, my impression was obviously coloured by being
               | around 45 at the time and I was used to program in many
               | different programming languages. Plus I grew up with
               | BASIC, Pascal and C.
               | 
               | There's going to be quite a different experience for
               | someone coming from Go/JS/Java and venturing into low
               | level programming for the first time!
               | 
               | That is not to say that all of the people being
               | enthusiastic about Zig is coming from those particular
               | languages, but I think that C is considered a scary
               | language for many people, so C alternatives tend to
               | attract people from higher level languages to a higher
               | degree than C itself.
               | 
               | When I eventually started on C3, I incorporated some
               | features from Zig. I ended up removing all of them as I
               | found them to be problematic: untyped literals combined
               | with implicit widening, unsigned error on overflow,
               | special arithmetic operators for wrap, saturation.
               | 
               | However, I am very grateful that Zig _explored_ these
               | designs.
               | 
               | From Odin I ended up including its array programming, but
               | for vectors only. I also adopted Odin's use of distinct
               | types.
               | 
               | But most of the C3 features are GCC C extensions plus
               | ASTEC inspired macros.
        
               | judofyr wrote:
               | Oh, wow! Huge respect for this comment. Thank you! This
               | is really cool to hear about.
        
               | nine_k wrote:
               | You can find a lot of the "showing me how to program"
               | sentiment is common among people who learn Lisp/Clojure,
               | Haskell, Erlang/Elixir, APL (oh, I mean, Numpy and
               | Spark), and any other language that significantly differs
               | from what you're used to. In the same vein, C is often a
               | revelation for those who cut their teeth tackling JS and
               | Python.
               | 
               | Indeed, Zig has interesting features that make you think
               | in ways you won't make when using C, like an ability to
               | offload large amount of computation to comptime code, or
               | using different allocators at different times (super
               | simple arena allocation per a game frame, for instance).
               | 
               | "A language that's not changing the way you think about
               | programming is not worth knowing."
        
             | baranul wrote:
             | This is a good point about narrative spreading, in addition
             | to marketing. People can become evangelized by their use of
             | certain languages or by comments from certain language
             | creators, then go on to attack others for using or even
             | just wanting to try other languages. This shouldn't be what
             | HN is about. It makes it look like HN has a language
             | approval list.
             | 
             | As for both C3 and Odin, they've been around for many
             | years, yet don't even have a Wikipedia page and have
             | relatively low numbers on GitHub. That comes across as more
             | time spent pushing or hyping on HN, than those languages
             | being considered a truly viable alternative by the general
             | public. Just weird, because you would think it should be
             | the other way around.
        
               | lerno wrote:
               | Did you know that Wikipedia editors will aggressively
               | remove Wiki entries about less known languages. There are
               | already several wiki articles on Odin by various authors
               | that have been removed over the years.
               | 
               | Talking about GitHub numbers, we can look at VLang, which
               | had an astronomical trajectory initially due to
               | overpromising and selling a language that would solve
               | long standing issues such as no manual memory management
               | but no GC needed etc.
               | 
               | Such viral popularity creates a different trajectory from
               | organically growing word of mouth such as in the Odin
               | case.
               | 
               | Vlang also has a Wikipedia page.
               | 
               | Is this then proof that it is a viable alternative to the
               | general public? This is what you argue.
        
               | baranul wrote:
               | Wikipedia and their processes are independent to any
               | language. It means that if Odin or other languages were
               | removed, they were likely judged as not popular or
               | relevant enough. That the Odin language is so old (around
               | 9 years), and still not on it, is indicative of it not
               | being as popular as various people are hoping.
               | 
               | The use of negative catch phrases and put downs by
               | competitors of Vlang has no bearing on the Wikipedia
               | process. They will not care about any competition or
               | politics among programming languages. The language either
               | meets their standard and proves its case, that it should
               | have a page, or not. Just like Zig, Nim, Rust, etc...
               | have done.
        
               | kelnos wrote:
               | I don't think I'd use popularity-contests like Github
               | stars or the presence of a Wikipedia page to judge a
               | language's popularity or future prospects.
        
           | 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.
        
             | nine_k wrote:
             | In other words, Zig is closer to the original C and maybe
             | Scheme, while C3 and Odin tend towards maybe Ruby (while of
             | course remaining capable of doing low-level stuff).
             | Correct?
        
               | Joshringuk wrote:
               | I have found C3 to be a generally simpler experience than
               | Zig, it's fun to use while being low level. The general
               | approach is aiming to be easy to use, personally I often
               | compare it to Go philosophically but with more similar
               | use cases to C and lower level.
        
               | lerno wrote:
               | Back in the day when C's closest competitor was Pascal, C
               | wasn't particularly hard to use. Pascal was easier for
               | manipulating strings and C better at doing low level data
               | manipulation.
               | 
               | But at the time there was little need for high level
               | abstractions, and it was fine to just allocate an array
               | with N number of entries and that was the maximum the
               | program allowed.
               | 
               | Today we're dynamically allocating memory with intricate
               | relationships, especially in object oriented programming.
               | 
               | This makes C look really hard to use - but it can
               | actually be much improved with just an improved string
               | library and a good dynamic array.
               | 
               | But there are also cross platform concerns for things
               | like networking and here C offers little to help.
               | 
               | Regardless whether you're using Zig, C3 or Odin you're
               | going to have a much easier time than C with straight up
               | libc.
               | 
               | So I think a better comparison is that Zig is a bit like
               | using the C++ containers. If you've ever struggled to
               | mutate a std::vector while iterating over it, you know
               | it's a bit complicated to figure out exactly what
               | functions fit where.
               | 
               | The final solution might be performant, but it's a lot
               | more to remember than say `iterator.remove_element()`
               | that you might encounter in some other language. However,
               | it does offer more ways to tweak it, and it's very
               | explicit in what happens.
        
           | AndyKelley wrote:
           | On ziglang.org the very first thing we advertise is:
           | 
           | > Focus on debugging your application rather than debugging
           | your programming language knowledge.
           | 
           | Clearly, you think the language fails at this criteria (your
           | subjective opinion). Please be honest and say that, rather
           | than implying that it's not explicitly one of the core design
           | principles of the language (objectively false).
        
             | lerno wrote:
             | (Funny story, I seem to have a bout of visual migraine at
             | the moment and misread your comment until just now and had
             | to remove what I wrote).
             | 
             | I didn't mean to give the impression that I'm putting down
             | Zig. It's more that I've noticed that people tend to frame
             | problems differently with Zig than with Odin.
             | 
             | To explain what I mean by framing, consider OO vs
             | procedural and the way OO will frame the problem as objects
             | with behaviour that interact, and procedural will frame the
             | problem as functions being invoked mutating data.
             | 
             | The difference isn't at all that stark between Odin and
             | Zig, but it's present nonetheless. And clearly Zig is doing
             | something which a lot of people like enjoy. It's just that
             | the person using Zig seems to enjoy different aspects of
             | programming (and it seems to me be in the spirit of "the
             | challenge of finding an optimal solution") than the person
             | using Odin.
        
         | 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)`
        
             | johnisgood wrote:
             | I 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 wrote:
               | Also, `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.
        
               | johnisgood wrote:
               | Do you think it is ever going to be removed, or do the
               | pros of having it outweigh the cons?
        
               | lerno wrote:
               | I don't like to say "never", because other things make
               | change that invalidates previous conclusions.
               | 
               | For example, let's say that for some reason macros were
               | removed (this is _very_ unlikely to happen, but as a
               | thought experiment), then the symmetry between macro /fn
               | definitions wouldn't be an argument anymore, and the
               | question could be revisited.
               | 
               | Similar things have happened before: the optional type
               | syntax changed from `int!` to the more mainstream `int?`.
               | So why did I stick with `int!` for so long? Because
               | initially it was called a "failable" and had different
               | semantics. Revisiting this syntax after other changes to
               | the syntax in 0.6.0, made it clear that `int?` was now
               | fine to use.
               | 
               | So that's why I don't say never. But it would need for
               | the situation to change in some way.
        
               | johnisgood wrote:
               | Thank you. I am not going to have "fn" stop me from
               | trying out C3 anyways.
               | 
               | There is a C (single header-only) library[1] that
               | determines CPU features at runtime (similar to that of
               | what libsodium does), so I might try to use that with C3
               | and implement BLAKE2. That might be a good starting
               | point, or perhaps even TOTP, my friend told me
               | implementing TOTP might give me some insight into the
               | language, but for that I will need base32 (I checked, it
               | exists[2]) and SHA{1,256,512}-HMAC, which may not be
               | available in C3, although there may be an OpenSSL binding
               | already, or perhaps I could directly use OpenSSL from C3?
               | The latter would be pretty cool if so.
               | 
               | Regarding the mentioned C library, it might not work,
               | because it is header-only, and it generates the C
               | functions using macros (see line 219). What do you think?
               | Would this work from C3?
               | 
               | [1] https://zolk3ri.name/cgit/cpudetect/tree/cpudetect.h
               | 
               | [2] https://github.com/c3lang/c3c/blob/master/lib/std/enc
               | oding/b...
               | 
               | ---
               | 
               | I checked base32.c3. I am comparing it to Odin's, which
               | can be found at https://github.com/odin-
               | lang/Odin/blob/master/core/encoding/.... Apparently they
               | added a way to gracefully handle error cases. Is it
               | possible to do so with the current C3 implementation?
               | 
               | Edit: I noticed "@require padding < 0xFF : "Invalid
               | padding character"", and there is
               | "encoding::INVALID_CHARACTER", so I presume we can handle
               | _some_ errors or invalid input gracefully. Although I
               | prefer Odin 's current implementation because you can
               | handle specific errors, e.g. not just "invalid
               | character", but invalid length (and others, see
               | base32.odin for more). Any thoughts on this?
               | 
               | Additionally, what are the differences between
               | @require padding < 0xFF : "Invalid padding character"
               | 
               | and                 @return? encoding::INVALID_PADDING,
               | encoding::INVALID_CHARACTER
               | 
               | exactly? If I want to handle invalid padding character, I
               | would have to get rid of "@require"?
               | 
               | Additionally, what if there are many more error cases? It
               | would be a "long line" of available error cases? Could I
               | use an enum of errors or something instead or something
               | similar to https://github.com/odin-
               | lang/Odin/blob/master/core/encoding/...?
               | 
               | BTW I like programming by contract, but I am not sure
               | that all error cases that Odin has could have a
               | "@require", and I am not sure if I would like to mix them
               | either, because what if I have a program where I want to
               | handle even "padding < 0xFF" specifically (in terms of
               | base32.c3), or let's say, I don't want it to fail when
               | "padding < 0xFF". Would I really need to implement my own
               | base32 encoding in that case, then, or what?
               | 
               | ---
               | 
               | Thank you for your time and help in advance!
        
               | lerno wrote:
               | For grabbing the CPU features, there is some rudimentary
               | implementation for x86 here: https://github.com/c3lang/c3
               | c/blob/master/lib/std/core/priva... but not properly
               | tested (which is to say, I would not count on it to work
               | properly).
               | 
               | The `@require` here is creating a contract. You can't
               | give a padding that is 0xFF, that's a programming error.
               | However, you might have data which is invalid - in that
               | case the typical error is INVALID_CHARACTER. To pass in a
               | too small buffer is a programming error since the output
               | buffer must be calculated first, so that's why that is
               | not an error either. This was a deliberate change to make
               | the API tighter.
               | 
               | So it's quite possible to add an "INVALID_LENGTH" error,
               | but that should only be there in case one does encryption
               | / decryption where the length cannot be easily determined
               | beforehand i.e. it's part of the unknown input which the
               | function determines. But in the Base32 implementation
               | this is not the case. Either use it with an allocator for
               | it to allocate sufficient memory for the data, or
               | calculate that the buffer you pass in is big enough (or
               | run into asserts if it isn't)
        
               | johnisgood wrote:
               | Oh thank you, that cpu_detect.c3 is exactly what I need,
               | the posted single-header library is almost the same in
               | terms of functionality.
               | 
               | BTW my last question still stands, however, that if there
               | is a C library that is only a single header file that
               | implements functions through macros, can it be used from
               | C3? In C, for what I posted, you would need to first do
               | "#define CPUDETECT_IMPL" and then include the header
               | file. Could it be done from C3 somehow? As in, could this
               | (or any) single-header library be used from C3?
               | 
               | And regarding the errors, can I have something like
               | "Error" (in Odin), or an enum of errors? Sorry for this
               | silly question, I realize I will have to read the source
               | code of the libraries first.
               | 
               | Thank you for your help!
        
               | lerno wrote:
               | It is possible to use a single-header library as part of
               | C3 libraries or your project. However, it must be noted
               | that this will inhibit the ability to cross compile, as
               | the compilation of the header is outsourced to the
               | natively installed C compiler.
               | 
               | For that reason it's not an option for the standard
               | library, but can certainly be useful for programs and
               | libraries.
               | 
               | For faults, they are usually defined with `faultdef`
               | which allows you to define one or more faults:
               | faultdef SOMETHING_WENT_SIDEWAYS, BIG_OOPS;
               | 
               | Then you use them as if they were constants:
               | if (x > 0) return BIG_OOPS?;
               | 
               | If they are defined in another module, say
               | "foo::bar::baz", then:                   if (x > 0)
               | return baz::BIG_OOPS?;
               | 
               | Using path shortening "foo::bar::baz::BIG_OOPS" would
               | also be valid, but is not necessary nor recommended.
        
               | lerno wrote:
               | If you want to have your own Base32 where giving a
               | padding = 0xFF instead returns an error, it's commonplace
               | to have a wrapper that will explicitly do the check and
               | return an error if it fails, and otherwise call the
               | function:                   macro String?
               | encode2(Allocator allocator, char[] src, char padding =
               | DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
               | {             if (padding >= 0xFF) return
               | INVALID_PADDING?;             return encode(allocator,
               | src, padding, alphabet);         }
               | 
               | Maybe a better place to ask these questions are on the
               | Discord if you have an account:
               | https://discord.gg/qN76R87
        
         | 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 ::.
        
               | gpderetta wrote:
               | I 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 wrote:
             | > Sure, but in practice I believe most developers would
             | find it intuitive to just type . everywhere.
             | 
             | Yeah, but _in practice_ I try not to produce write-only
             | code.
             | 
             | Code is for reading more than for writing, hence make it
             | easier to read. If it becomes easier to write as a side-
             | effect, then so be it.
        
           | 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 .
        
             | lerno wrote:
             | C3 has "path shortening", so for example given `open(...)`
             | in std::io::file is usually used as `file::open(...)`. If
             | we would to write this as `file.open(...)`. Consider now
             | the case of mistyping `open`: `file.openn(...)`. Is this
             | (A) mistyping the function open in module `std::io::file`
             | or is it (B) the global/local `file` is missing from the
             | current scope?
             | 
             | Also, "io", "file", "random" etc are commonly used
             | variables, so the issue with shadowing is real.
             | 
             | `File file = file::open(...)` is completely unambiguous and
             | fine. `File file = file.open(...)` on the other hand would
             | be bad.
             | 
             | If the language had flat modules, or no path shortening,
             | then it would be possible.
        
               | WalterBright wrote:
               | > Is this (A) mistyping the function open in module
               | `std::io::file` or is it (B) the global/local `file` is
               | missing from the current scope?
               | 
               | D uses a spell checker for undefined identifiers, and the
               | dictionary is all the identifiers in scope. It has about
               | a 50% success rate in guessing which identifier was
               | meant, which is quite good.
               | 
               | > Also, "io", "file", "random" etc are commonly used
               | variables, so the issue with shadowing is real.
               | 
               | If the same identifier is accessible through multiple
               | lookup paths, an error is issued. If a local variable
               | shadows a variable in an outer scope, and error is
               | issued.
               | 
               | We've developed this over several years, and it works
               | quite well.
               | 
               | Path shortening can be done with:                   alias
               | open = file.open;
               | 
               | or:                   import io: open;
        
               | lerno wrote:
               | If I would have liked, I could have done something like
               | `import std::io::file as file;` but I noticed that we
               | keep getting this issue that we're renaming things all of
               | the time, and usually in the same way. This is why path
               | shortening is there. To directly get something like the
               | informal `file_open` namespacing in C programs.
        
               | Joshringuk wrote:
               | Standardisation of code and examples across codebases is
               | a nice result of this too. This makes the code easier to
               | learn and share
        
               | kelnos wrote:
               | I feel like path shortening is the issue, and IMO it's an
               | unnecessary feature. I don't think most programmers are
               | bothered by the need to explicitly import what they use.
               | I'd personally _prefer_ to explicitly import what I use,
               | and refer to it in whatever way the import statement
               | would imply.
               | 
               | In Rust where modules share a namespace with other
               | identifiers, I just pick different variable names, or
               | write my imports so they don't conflict. It's not that
               | big a deal.
        
           | 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.
        
             | lerno wrote:
             | But you have to. Ambiguities hint at lack of redundancies
             | that also affects code reading. When you quickly scan
             | something like `file.open` vs `file::open` the former is
             | also more unclear to a reader without more context.
        
         | 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.
        
         | Asooka wrote:
         | I like it. It disambiguates when you're referring to a member
         | of an object -- myobj.member vs referring to a global object by
         | its full name -- module::function. I guess you could say the
         | IDE can colour the two differently, but after spending a lot of
         | time working with various code review tools of varying quality,
         | I have come to really appreciate having the program text be as
         | explicit as possible. If you find it so disagreeable, can't you
         | configure your IDE to visually replace that syntax with a
         | single dot and also automatically convert a single dot to two
         | colons when typing a namespace?
        
         | mort96 wrote:
         | I like to quickly at a glance be able to distinguish between
         | "this is a member access on an object" and "this is referencing
         | something in a module".
         | 
         | I like that the compiler can distinguish those two things too,
         | so that I can refer to things within modules even if I happen
         | to also have a local variable with the same name. Go sometimes
         | annoys me because I need to rename a module or a variable just
         | because the syntax doesn't distinguish between the two things.
        
           | throwawaymaths wrote:
           | > distinguish between "this is a member access on an object"
           | and "this is referencing something in a module".
           | 
           | zig: what's the difference?
        
             | lerno wrote:
             | There is an overlap between module and class namespacing
             | through static members and functions. Zig sees this and
             | says "let's only have the latter" (on structs), which means
             | among other things that in Zig a file is a structure. Most
             | other languages says "let's have both".
             | 
             | In C3 it goes the other way despite having methods, and
             | says "let's not allow static variables or methods".
             | 
             | This also goes hand in hand in the language approaches
             | between open/close. Zig is very strongly "closed" and C3 is
             | very much "open" (adding methods to types anywhere,
             | appending to modules anywhere etc)
             | 
             | It's an interesting contrast that leads to very different
             | code layouts.
        
             | mort96 wrote:
             | Surely Zig differentiates between, say, a function in a
             | module, and a member on an object? Or are "modules"
             | literally just instances of classes or something?
        
               | lerno wrote:
               | No, they are the same.
        
       | 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.
        
         | lerno wrote:
         | Yes, this is a very real problem that I've also written about:
         | https://c3.handmade.network/blog/p/8486-the_case_against_a_c...
        
       | 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)
        
           | fuzztester wrote:
           | thanks.
        
           | tialaramex wrote:
           | Notably 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 wrote:
             | Yes: https://c3.handmade.network/blog/p/8486-the_case_again
             | st_a_c...
        
       | 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.
        
         | baranul wrote:
         | Arguably, 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
         | 
         | [2] https://github.com/c3lang/c3c
        
           | lerno wrote:
           | Isn'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 wrote:
             | This 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.
        
               | lerno wrote:
               | I asked and got Bas's[1] permission to use C3 as a name
               | when I first started out.
               | 
               | [1] Bas van den Berg, the author of C2.
        
         | jstimpfle wrote:
         | There is no spiral rule, that is a misconception. Look up how
         | "declaration follows usage" in C. E.g.
         | https://eigenstate.org/notes/c-decl
         | 
         | While this rule has become somewhat diluted when C developed
         | and gradually took on features from C++ (like types in function
         | parameters), it's still very helpful to understand the guiding
         | principle. (But those inconsistencies that crept in over time
         | are also the reason why newer languages don't do that anymore).
        
       | 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.
        
             | lerno wrote:
             | Oh, 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-...
             | 
             | At the top level and `@if` attribute is used to achieve the
             | same thing: https://c3-lang.org/language-
             | common/attributes/#if
        
               | owlstuffing wrote:
               | Ah. The top-level lang description claims "No
               | preprocessor", but my definition of that word doesn't
               | appear to be the same as yours :/
        
               | lerno wrote:
               | The difference here is that a preprocessor runs before
               | parsing and semantic analysis. In C3 compile time if runs
               | in the analysis step, so after parsing.
               | 
               | So the macros and compile time execution occurs after
               | parsing in C3, but in C everything happens at lexing,
               | before the code is parsed.
        
               | owlstuffing wrote:
               | That strategy will backfire when the grammar changes in a
               | later release. A pre-parse step is necessary for code
               | that targets different compiler releases.
        
               | lerno wrote:
               | Now I'm confused, what do you mean? What grammar changes?
        
               | owlstuffing wrote:
               | Imagine v2.0 introduces a new feature that requires a
               | parser change--one that v1.0 wouldn't be able to parse.
               | $if $defined(C3_V2_PLUS):             // new feature
               | fn f = \ -> foo(); // this won't parse in v1.0
               | $else           Callback f = ...;       $endif
               | 
               | This is also an issue if a future version of C3
               | introduces language level support, allowing newer
               | compilers to compile code as if it were written for an
               | earlier version. While this approach works well when
               | teams standardize on a specific version's feature set,
               | they may still want to take advantage of performance
               | improvements in the latest compiler.
               | 
               | That said, this is a niche case and not something I'd
               | consider a dealbreaker.
        
               | lerno wrote:
               | Ah, that is indeed true. However, the plan is to have the
               | language fixed at 1.0, only updating stdlib and tooling
               | after that.
        
               | owlstuffing wrote:
               | Well, if your language gains traction that plan may not
               | succeed. For your sake, I hope that's the case :)
        
               | sriram_malhar wrote:
               | You don't need an ifdef.
               | 
               | You just need a CLI option like java's --source, where
               | you specify the source compatibility with different
               | language versions.
        
               | owlstuffing wrote:
               | You do, that's the point here. You need ifdefs in this
               | example to selectively compile the same code with
               | different compilers, or different language levels with
               | the same compiler. In either case C3 will fail while
               | parsing a newer feature with an older compiler or lang
               | level.
        
       | johnisgood wrote:
       | @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 wrote:
         | Blake2 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 wrote:
           | > 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 wrote:
       | Does it allow you to make functions weak? Can you do something
       | like gcc's constructor attribute?
        
       | djmips wrote:
       | Does it have native fixed point types?
        
       | moktonar wrote:
       | Why the "fn" token?
        
       | CyberDildonics wrote:
       | I 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 wrote:
         | Destructors 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.
        
       ___________________________________________________________________
       (page generated 2025-04-04 23:01 UTC)