> Quite long devlog coming up, apologies—I got a little carried away with this one!
mlugg, please don't apologize for creating something I actually want to read. I'm drowning in low effort garbage, the in depth technical explanation is a refreshing breath of fresh air.
Might as well apologize for creating a language without a garbage collector, sure most people are unwilling to think, but some of us like nice things and are actually willing to apply effort.
Why I've moved more to a couple of language/software dev discords and away from Hacker News. Way too much uninteresting AI nonsense on here for a while now.
That and the continual pushing of Zig and Rust to ridiculous levels, like HN had investments in them or were getting payouts, and as if few to no other programming languages exist.
Interesting read, even as someone who isn't using Zig.
I wonder, these arbitrary-width integers... Is it actually even really worth it? My intuition is to prefer manually packing/unpacking things instead (in any language, even C that has bit width for struct fields), because it gives me a better mental picture of the code that is actually generated. Particularly for something like an signed odd-bit integer - what kind of code gets generated for sign-extension, a presumably common operation?
Does anybody have other experiences with them, one way or the other?
IMO they're fantastic. You can write out a bit layout from a CPU's manual fro example and you can just use whatever bit width the manual specifies, and the compiler takes care of figuring out all the underlying manipulation for you. Which results in much more readable code because you don't have to worry about packing/unpacking it because the compiler will do that for you.
If you use LLVM at least, they expand to a lot of code which is repeated on every operation. There’s a point where the inline code will just blow the instruction cache and just create unacceptable binary bloat.
> Consider, for instance, bitcasting a [2]u8 to a u16. Under the old semantics, the result of this operation depends on the target endian: on big-endian targets, the first array element became the 8 most significant bits, whereas on little-endian targets, the first array element became the 8 least significant bits. Under the new semantics, because we only care about logical bit representation (which is endian-agnostic), the operation behaves identically on every target:
This is a huge mistake. You would never expect something like bitCast to do this.
I don't understand this approach. Why change something so simple and low level to be complicated and high level?
Just don't allow casting to u24, as it makes no sense unless you define u24 to be u32 sized as I think c standard does.
I think this approach as an idea is bad but at least just add another built-in that implements this higher level idea to not break a simple expectation and current behavior?
I may be damaged from working on IC hardware design and various weird architectures, but I truly can’t comprehend why you’d think this doesn’t make sense.
Yeah, if your architecture doesn’t support 24-bit int it maps to 32-bits. But it also declares that the numbers you’re storing should never be larger than 2^24. It’s about type safety, and also run time checks in safe mode I believe. Bitcasting three bytes to a 24-bit type makes just as much sanse as casting 4 bytes to 32-bit. Theres zero reasons to introduce arbitrary artificial constraints on what you can do based on details of (most of) the underlying architectures, which doesn’t even matter for the operation you’re performing.
> As a general rule, the new semantics tend to match the behavior of the old semantics on little-endian targets.
They've basically said that bit casting is going to be little endian. This simplifies things for the 100% of people that are on little endian machines, while making the code still work for the 0% of people (rounded to the nearest 0.0000001%) that are using big endian machines.
This change + the existing packed struct logic will be great for working with bit packed binary headers w/o having to manually twiddle so much about the bit handling along the way.
OT: I'm always surprised at how popular Zig discussions get here, or Youtube and other medias.
Don't get me wrong, I love Zig and I think it's a great C replacement, but I'm very confused on why C3 or Odin rarely get any attention at all, despite being in the same C-replacement crowd.
But still surprised at what Zig does better than these other projects? Is Andrew much better at marketing/promoting the language? He's very hard to dislike.
> Don't get me wrong, I love Zig and I think it's a great C replacement, but I'm very confused on why C3 or Odin rarely get any attention at all, despite being in the same C-replacement crowd.
Doesn't matter as neither will see significant adoption.
Zig has a really great backwards compatibility story with C, and it also is a better C compiler even if you don't write a single line of Zig. It's not hard to see why that is popular.
Zig was the first to appear on my radar. I believe I saw Andrew's first (?) talk called the "The road to Zig 1.0" where he communicated his vision very clearly in a way that must have sounded like the promise of the holy land for C programmers who were stuck in C hellscape. Maybe it was even an earlier video where he talked after a rust talk but it was essentially the same message.
Maybe the best marketing is to establish your vision and stick to it over the years ?
In any case c3 didn't exist, I had never stumbled on a talk of Odin's creator and its syntax seemed more foreign (I only knew C back then) so I started rooting for zig.
Even though it's not 1.0 yet, zig seems more ambitious (incremental compilation ! comptime ! translate-c ! logical bitcasting !) and committed to the vision of C companion/replacement. That for me is enough to still be hyped ten years after.
> I'm very confused on why C3 or Odin rarely get any attention at all, despite being in the same C-replacement crowd
Your observation is valid, and many would say because something smells very fishy with what HN is doing. Zig is pushed at extremely nonsensical levels on HN, despite there being very worthy and interesting language contenders in the category: C3[1], Odin[2], Vlang[3], Dlang[4], Zen C[5], etc...
We rarely get to see news about these other languages, but instead are constantly saturated with and hit over the head with news about Zig (even though it's still in beta). And as if people don't have interests in or don't want to see anything about other young or newer languages in the category.
FTA: “Under the new semantics, because we only care about logical bit representation (which is endian-agnostic), the operation behaves identically on every target: the first array element becomes the 8 least significant bits”
I wouldn’t call that endian-agnostic. It’s explicitly picking little-endian.
It also makes things look weird for beginners. I know how it works, but in the
test "bitcast [2]u3 to @Vector(3, u2)"
example, turning two 3-bit values [abc def] into three 2-bit values [bc fa de] is way less intuitive than turning it into [ab cd ef].
Writing linkers must be incredibly rewarding - go has its own, there's mold, there's LLD, there's the OG GNU bfd LD and now Zig has one too! I am sure there's a Rust one too - Wild!
Every one of them is faster than the others too lol! Mold for one tries really hard to be GNU ld and to be useful as an independent linker most have to - I guess Zig/Go ones are purpose built so at least those don't duplicate GNU ld compatibility.
When I first found out about bit fields in C, I was left wondering what the order of bits was in a byte, eventually I convinced myself it doesn't matter, since the byte is the smallest I/O unit, and lived with the fact that casting between bitfields and bytes was UB (or unspecified, I can't remember), and as such, was another thing I wasn't suppossed to do when writing C.
All this to say that Zig just keeps cleaning up and giving well-defined semantics to warts I learned to live with in C.
25 comments
[ 3.6 ms ] story [ 44.0 ms ] threadmlugg, please don't apologize for creating something I actually want to read. I'm drowning in low effort garbage, the in depth technical explanation is a refreshing breath of fresh air.
Might as well apologize for creating a language without a garbage collector, sure most people are unwilling to think, but some of us like nice things and are actually willing to apply effort.
I wonder, these arbitrary-width integers... Is it actually even really worth it? My intuition is to prefer manually packing/unpacking things instead (in any language, even C that has bit width for struct fields), because it gives me a better mental picture of the code that is actually generated. Particularly for something like an signed odd-bit integer - what kind of code gets generated for sign-extension, a presumably common operation?
Does anybody have other experiences with them, one way or the other?
This is a huge mistake. You would never expect something like bitCast to do this.
I don't understand this approach. Why change something so simple and low level to be complicated and high level?
Just don't allow casting to u24, as it makes no sense unless you define u24 to be u32 sized as I think c standard does.
I think this approach as an idea is bad but at least just add another built-in that implements this higher level idea to not break a simple expectation and current behavior?
Yeah, if your architecture doesn’t support 24-bit int it maps to 32-bits. But it also declares that the numbers you’re storing should never be larger than 2^24. It’s about type safety, and also run time checks in safe mode I believe. Bitcasting three bytes to a 24-bit type makes just as much sanse as casting 4 bytes to 32-bit. Theres zero reasons to introduce arbitrary artificial constraints on what you can do based on details of (most of) the underlying architectures, which doesn’t even matter for the operation you’re performing.
> As a general rule, the new semantics tend to match the behavior of the old semantics on little-endian targets.
They've basically said that bit casting is going to be little endian. This simplifies things for the 100% of people that are on little endian machines, while making the code still work for the 0% of people (rounded to the nearest 0.0000001%) that are using big endian machines.
Don't get me wrong, I love Zig and I think it's a great C replacement, but I'm very confused on why C3 or Odin rarely get any attention at all, despite being in the same C-replacement crowd.
But still surprised at what Zig does better than these other projects? Is Andrew much better at marketing/promoting the language? He's very hard to dislike.
Doesn't matter as neither will see significant adoption.
Maybe the best marketing is to establish your vision and stick to it over the years ?
In any case c3 didn't exist, I had never stumbled on a talk of Odin's creator and its syntax seemed more foreign (I only knew C back then) so I started rooting for zig. Even though it's not 1.0 yet, zig seems more ambitious (incremental compilation ! comptime ! translate-c ! logical bitcasting !) and committed to the vision of C companion/replacement. That for me is enough to still be hyped ten years after.
Your observation is valid, and many would say because something smells very fishy with what HN is doing. Zig is pushed at extremely nonsensical levels on HN, despite there being very worthy and interesting language contenders in the category: C3[1], Odin[2], Vlang[3], Dlang[4], Zen C[5], etc...
We rarely get to see news about these other languages, but instead are constantly saturated with and hit over the head with news about Zig (even though it's still in beta). And as if people don't have interests in or don't want to see anything about other young or newer languages in the category.
[1]: https://github.com/c3lang/c3c
[2]: https://github.com/odin-lang/odin
[3]: https://freedium-mirror.cfd/https://levelup.gitconnected.com...
(The V Language: The Best Parts of Go, Rust, and Python — All in One)
[4]: https://freedium-mirror.cfd/https://levelup.gitconnected.com...
(The D Language: A Better C/C++ Alternative Only a Few Programmers Know)
[5]: https://github.com/zenc-lang/zenc
No jokes aside, these posts are the best advertisements of the language.
And I truly like their AI stance.
I wouldn’t call that endian-agnostic. It’s explicitly picking little-endian.
It also makes things look weird for beginners. I know how it works, but in the
example, turning two 3-bit values [abc def] into three 2-bit values [bc fa de] is way less intuitive than turning it into [ab cd ef].Every one of them is faster than the others too lol! Mold for one tries really hard to be GNU ld and to be useful as an independent linker most have to - I guess Zig/Go ones are purpose built so at least those don't duplicate GNU ld compatibility.
All this to say that Zig just keeps cleaning up and giving well-defined semantics to warts I learned to live with in C.