[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)