HNHacker News
TopNewBestAskShowJobs

lerno

1,425 karma · joined April 1, 2014

submissionscomments
lerno··on Programming language C3 release 0.7.8 is out
C3 is a language designed as an evolution of C, without retaining strict backwards compatibility, but excellent interop with C.

This version brings - among other things: struct splatting (some_call(...a_struct, 1, 2)) and vector swizzle initialization (int[<3>] x = { .xy = 3, .z = 5 }). Together with other improvements and fixes.

Some older post on C3:

- https://news.ycombinator.com/item?id=43569724

- 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/ Repository with link to various C3 resources and projects:

- https://github.com/c3lang/c3-showcase

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

lerno··on Ultima VII Revisited
Ultima 4 was good story wise, but the combat was extremely tedious with each in your party only being able to take a single step per turn. This was particularly annoying when facing easy to beat foes. The SSI AD&D games which only came out a little after U4 had a superior system, where each character in the party could move multiple steps (depending on stats) and so could the mosters. That system, while also repetitive, was much faster for combat, not to mention much more strategic and fun.

Later Ultimas, like U7 instead went for a streamlined realtime battle which was much better. That went overboard with the at the time infamous U8

lerno··on Whatever Happened to String Theory?
Over 25 years ago I was doing ny final thesis on string theory for my Masters degree. The more I read, the more I went ”this could not possibly be right”. I ended up taking a break to work to get perspective on things and decide whether I wanted to continue pursuing a career in theoretical physics. I never went back. And given that in this field, things have been stagnant for those 25 years, it seems my impressions were quite on the mark.

Having so many things required to make it work, that we could not verify always rubbed me the wrong way, as was the ability to always be able to add just one more patch to make it outlive each experimental or theoretical setback.

lerno··on C3 vs. C: A cleaner C for 2025? [video]
Maybe this, where a Zig user tries out C3?

https://alloc.dev/2025/05/29/learning_c3

lerno··on Zig and the design choices within
I answered above.
lerno··on Zig and the design choices within
If you are comparing Zig to Rust and C++, which are very well known to be difficult to learn, then that is not really saying anything about the ease of learning it. Compare it to Swift, D or Odin. Is it "incredibly simple" compared to those languages as well?

Similarly, one can claim that pretty much anything compiles "incredibly fast" if one compares with Rust, C++ and Swift.

But comparing to worst in class doesn't actually say anything.

One note about this:

> If you have not written a real application in Zig and evaluated it for vulnerabilities, but are claiming that creating Zig was irresponsible, and using it is too; you are cargo culting.

I don't know what this has to do with my comments at all, but I want to point out that you are using "cargo culting" wrong. This describes imitating practices of something successful, thinking that by this imitation, success will follow as well.

> No one reasonable has claimed that memory safe languages should not exist,

Again, I have not talked anything about whether memory safe languages should or should not exist. You are confusing me with someone else.

lerno··on Zig and the design choices within
Embergen is 400kloc Odin, it compiles in about 2s. No incremental compilation or caching to speed it up.

And this is with LLVM as backend.

lerno··on Zig and the design choices within
This is just a convenient excuse. If Zig is to be fast to compile, it doesn’t help to make excuses for it.

Saying something it ”fast enough” because one is comparing with even slower languages is likely what made both Rust and Swift so slow to compile - they all just compared with C++, and it wasn’t until much later - when larger projects appeared - that the problem was taken more seriously. But at that time core architectural and language design concerns were already locked in.

This is why it’s not good for Zig to rest on its laurels and compare with worst of the class. And actually, faster Zig compile times benefits Jai, Odin and C3 as well, because then THOSE compilers can’t afford to slow down either. It’s a win-win.

If we compare with the worst though, then that’s a lose-lose proposition.

lerno··on Zig and the design choices within
”Zig builds C faster than most C compilers” is a nonsense statement, which I don’t know how to answer.

The fact is simply that despite Zig uses LLVM as a backend in the same way Odin and C3 does, it compiles much slower. Exactly why that is, is something I can only guess at, but the fact is that Zig cached is still much slower to compile than Odin or C3.

(There are a few possible candidates as to why this is so that I identified and can share if it is interesting)

In any case, Zig is only ”fast to compile” if you compare to the triad of infamously slow languages: Swift, C++ and Rust.

Anything else is just hype.

lerno··on Zig and the design choices within
It uses LLVM as the backend yes.
lerno··on Zig and the design choices within
Odin, Jai, C3, C.
lerno··on Zig and the design choices within
I have never heard anyone calling Zig "famously simple" before. In fact, people tend to say it has quite the learning curve.

Of course, caveats apply: it is certainly simple compared to some languages, but certainly not compared to others. "Famously simple" seems to indicate it is one of the simplest languages to learn, which seems wrong unless there are some serious qualifications to that statement?

lerno··on Nim 2.2.6
I feel qualified to offer a guess as to why: in Zig (and Odin) reuse is mainly done through what basically is templates. This reduces the need for vtables only when true ”plugin” type of objects are the only solution. For Zig and Odin, the only stdlib usages are for allocators and streams. These few usecases are way too few to motivate a full fledged interface feature, and consequently it’s not added. So it’s both a lack of usecases, as well as a desire to prefer templates over interfaces for reuse, typically due to performance concerns.
lerno··on Zig builds are getting faster
I should add that there are a few candidates:

1. Zig uses three(!) frontend IRs, Odin and C3 only one.

2. Zig relies heavily on comptime to provide most of its language features. C3, which has a similar set of features, doesn’t encourage excessive use of compile time and offers more features built into the language (for example format checking is a builtin, whereas in Zig it’s userland, even if C3 has the capability to do it like Zig). Although note that Zig only checks code directly traced, whereas C3 will check all code, and so will - esp for simple code - check much more code than Zig does.

3. Zig generates A LOT of code for even just a ”safe” Hello World.

On top of that, maybe there are just some other inefficiencies that hasn’t been addressed yet by the Zig team?

Even though I have stakes in the game I hope Zig gets faster. We need to move away from the illusion that Swift, C++ and Rust compilation speeds are anywhere near acceptable.

lerno··on Zig builds are getting faster
While LLVM certainly is a problem, consuming over 90% of compile times both for C3 and Odin, it should be noted that both languages compile MUCH faster than Zig, achieving in general sub second compile times while using LLVM and without incremental compilation. So the question could be asked: ”what is making Zig so slow to compile” as both languages have similar feature sets compared to that of Zig.
lerno··on C3 Language 0.7.6 adds generic inference and shebang compatibility
This release adds shebang support, and simple generic parameter inference (which doesn't have that much use in C3 compared to languages that have per function/type generics, rather than generic modules). There are some conveniences, like in-place compile time concat with `+++=`. And of course that slices and arrays of types with an implemented `==` overload can now be compared as well.

There are plenty of fixes, but still half of what was in the 0.7.5 release.

Next version will focus on stdlib additions.

Some older post on C3:

- https://news.ycombinator.com/item?id=43569724

- 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/

Repository with link to various C3 resources and projects:

- https://github.com/c3lang/c3-showcase

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

lerno··on Zig feels more practical than Rust for real-world CLI tools
It is well known that Swift set out in design without any prior knowledge of the language it was replacing (Objective-C), with only the most junior in the team having used it to any greater extent.

Instead Swift was designed around the use-cases the team was familiar with, which would be C++ and compilers. Let's just say that the impedance between that and rapid UI development was pretty big. From C++ they also got the tolerance for glacial compile times (10-50 times as slow as compiling the corresponding Objective-C code)

In addition to that they did big experiments, such as value semantics backed by copy-on-write, which they thought was cool, but is – again – worthless in terms of the common problem domains.

Since then, the language's just been adding features at a speed even D can't match.

However, one thing the language REALLY GETS RIGHT, and which is very under-appreciated, is that they duplicated Objective-C's stability across API versions. ObjC is best in class when it comes to the ability to do forward and backwards compatibility, and Swift has some AWESOME work to make that work despite the difficulties.

lerno··on Zig feels more practical than Rust for real-world CLI tools
I can't speak for Zig users, but an interesting alternative to just new/delete or malloc/free and various garbage collection strategies is pervasive use of temp allocation using arenas, such as Jai and Odin's temp allocators (essentially frame allocators) and C3's stack-like temp allocator. Zig also favours using arenas, but more ad hoc.

What happens in those cases is that you drop a whole lot of disorganized dynamic and stack allocations and just handle them in a batch. So in all cases where the problem is tracking temporary objects, there's no need to track ownership and such. It's a complete non-problem.

So if you're writing code in domains where the majority of effort to do manual memory management is tracking temporary allocations, then in those cases you can't really meaningfully say that because Rust is safer than a corresponding malloc/free program in C/C++ it's also safer than the C3/Jai/Odin/Zig solution using arenas.

And I think a lot of the disagreement comes from this. Rust devs often don't think that switching the use of the allocator matters, so they argue against what's essentially a strawman built from assumed malloc/free based memory patterns that are incorrect.

ON THE OTHER HAND, there are cases where this isn't true and you need to do things like safely passing data back and forth between threads. Arenas doesn't help with that at all. So in those cases I think everyone would agree that Rust or Java or Go is much safer.

So the difference between domains where the former or the latter dominates needs to be recognised, or there can't possibly be any mutual understanding.

lerno··on Zig feels more practical than Rust for real-world CLI tools
Unfortunately Swift is a mess of a language, trying to put as many language features in there as possible. While still not getting close to being a good replacement for Objective-C. AND it's the slowest language to compile among languages with a substantial adoption.

It's just pig-headedness by Apple, nothing more.

lerno··on Zig feels more practical than Rust for real-world CLI tools
I find some of Rust dev reactions to this article pretty embarrassing. As if memory safety was some holy grail only provided by Rust.

Here is a bunch of more memory safe languages that are more popular than Rust: Python, Java, JS ... should I continue?

But wait, there's more. Can Rust verify that arbitrary in-data is valid, like having contracts statically checked at compile time? It can't, and so then by the same logic as some people calling non-Rust languages "gibberish" for not having a borrow checker, should we call Rust "gibberish" because it can't check those invariants at compile time like C3 can do?

No?

Then get off that high horse.

And by the way, my great fear is that we'll get more adoption by Rust while at the same time Rust is unable to improve the compile times. C++, Swift and Rust, the three horsemen of infamously long compile times.

The borrow checker isn't the main problem, just like C++'s problems isn't complex template messages – it's that both takes so long to compile. Time you could spend reading and testing the code. Long compile times inhibits refactoring and cause bugs to stay unfixed.

lerno··on C3 solved memory lifetimes with scopes
What is "incredibly dangerous"? Having contracts that can catch errors at compile time?
lerno··on C3 solved memory lifetimes with scopes
"Incremental compilation is fast", is something people only talk about when normal compilation speeds are abysmal. Sadly, C++ set the expectations here, which made both Rust and Swift think that compilation times in the minutes is fine.

If your code compiles in 1 second from scratch then what do you need incremental compilation for?

lerno··on C3 solved memory lifetimes with scopes
Ok then I understand what you mean (I couldn't respond directly to your answer, maybe there is a limit to nesting in HN?).

Let me respond in some more detail then to at least answer why C3 doesn't have RAII: it tries to the follow that data is inert. That is – data doesn't have behaviour in itself, but is acted on by functions. (Even though C3 has methods, they are more a namespacing detail allowed to create methods that derive data from the value, or mutate it. They are not intended as organizational units)

To simplify what the goal is: data should be possible to create or destroy in bulk, without executing code for each individual element. If you create 10000 objects in a single allocation it should be as cheap to free (or create) as a single object.

We can imagine things built into the type system, but then we will need these unsafe constructs where a type is converted from its "unsafe" creation to its "managed" type.

I did look at various cheap ways of doing this through the type system, but it stopped resembling C and seemed to put the focus on resource management rather than the problem at hand.

So that is why it's closer to C than Rust.

lerno··on C3 solved memory lifetimes with scopes
Alloca would not allow you to pass data from the current scope up to a parent scope.
lerno··on C3 solved memory lifetimes with scopes
All of that is out of scope for a C-like though. Once you set the constraints around C, there will be trade-offs. Rust is a high level language.
lerno··on C3 solved memory lifetimes with scopes
Let me paste the introduction in the post, and let's see how much it claims that C3 has memory safety:

Modern languages offer a variety of techniques to help with dynamic memory management, each one a different tradeoff in terms of performance, control and complexity. In this post we’ll look at an old idea, memory allocation regions or arenas, implemented via the C3 Temp allocator, which is the new default for C3.

The Temp allocator combines the ease of use of garbage collection with C3’s unique features to give a simple and (semi)-automated solution within a manual memory management language. The Temp allocator helps you avoid memory leaks, improve performance, and simplify code compared to traditional approaches.

Memory allocations come in two broad types stack allocations which are compact, efficient and automatic and heap allocations which are much larger and have customisable organisation. Custom organisation allows both innovation and footguns in equal measure, let’s explore those.

lerno··on C3 solved memory lifetimes with scopes
What destructor?
lerno··on C3 solved memory lifetimes with scopes
*see
lerno··on C3 solved memory lifetimes with scopes
You lost me there I'm afraid.
lerno··on C3 solved memory lifetimes with scopes
Not possible to nest and possible to run down out of stack memory quickly. That said, C3 has a `@stack_mem(1024; Allocator mem) { ... }` which allows to allocate a part of the stack and use that as an allocator with fallback.
← PreviousPage 3 of 13Next →