Live data from Hacker News

Packed structs in Zig make bit/flag sets trivial

devlog.hexops.com

111–120 of 147 posts

Re: Packed structs in Zig make bit/flag sets trivial

#111
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

Yes it would need to be: if ((mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { ... } ...which is quite a mouthful.

What about?

    if (mask & WGPUColorWriteMask_Alpha & WGPUColorWriteMask_Blue) {
        // alpha and blue are set..
    }

Re: Packed structs in Zig make bit/flag sets trivial

#112
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

Yes it would need to be: if ((mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { ... } ...which is quite a mouthful.

I use:

    if (all_of(mask, WGPUColorWriteMask_Alpha | WGPUColorWriteMask_Blue))
with all_of() being a #define. Likewise none_of(), any_of().

No need for special operators.

Re: Packed structs in Zig make bit/flag sets trivial

#113
post #95

Earlier quoted context omitted.

Bit fields are portable since ages, since C89. Just pack it, use the smallest base type and don't leave holes. We were using them in perl5 forever, and this compiles on more platforms with more compilers then you know. Just use -mms-bitfields on mingw and use unsigned short instead of just unsigned. E.g. https://www.nntp.perl.org/group/perl.perl5.porters/2008/02/m... for tricks.

> Bit fields are portable since ages, since C89. Wrong. N1256 (ISO C99 spec), for instance, explicitly states in 6.7.2.1.10: The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. Look it up.

In theory yes, in practice no. And the committee usually has no idea.

Re: Packed structs in Zig make bit/flag sets trivial

#114

Earlier quoted context omitted.

The in-memory representation of bit fields is implementation-defined. Therefore, if you're calling into an external API that takes a uint32_t like in the example without an explicit remapping, you may or may not like the results. In practice, everything you're likely to come across will be little endian nowadays, and the ABI you're using will most likely order your struct from top to bottom in memory, so they will lo…

> In practice, everything you're likely to come across will be little endian nowadays The internet?

Not really relevant to a discussion about CPUs and compiler implementations...

Re: Packed structs in Zig make bit/flag sets trivial

#115

Earlier quoted context omitted.

Yes it would need to be: if ((mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { ... } ...which is quite a mouthful.

What about? if (mask & WGPUColorWriteMask_Alpha & WGPUColorWriteMask_Blue) { // alpha and blue are set.. }

> `mask & WGPUColorWriteMask_Alpha & WGPUColorWriteMask_Blue`

If WGPUColorWriteMask_Alpha and WGPUColorWriteMask_Blue doesn't share bits, isn't this garanteed 100% to be false?

Re: Packed structs in Zig make bit/flag sets trivial

#116
post #44

Earlier quoted context omitted.

Is it something I'd ever want to rely on third-party functionality for?

C has them and their implementation seems to be universally disliked. Using an external crate with an implementation that people do like, with the possibility to substitute another if you disagree, seems better than to force a specific implementation into the language (that people will then replace with external dependencies or that people will learn to avoid as a concept).

Sometimes, there's value in providing a standard way of doing things. Even if it isn't perfect in all cases (or even a median case), then at least most people coalesce around how it's used and its limitations.

But yeah, sometimes it's better to have options. If it's common functionality though, there will likely be 1000 different implementations of it that all just slightly differ [0]. Perhaps it were better for that effort to be put into making the standard better.

I don't think there's a universally correct answer by any means, but for something so common as bitflags, I think I personally lean towards having a standard. Replacing an implementation wholesale feels like it should be reserved as a last resort.

Either way, I think mature pieces of software (languages especially) strive to provide a good upgrade path. Inevitably, the designers made something that doesn't match current needs. Even if it's just that "current needs" changed around them.

[0]: And if we subscribe to Sturgeon's Law, 90% of those are crap, anyway. Though they might not appear so on the surface...

Re: Packed structs in Zig make bit/flag sets trivial

#117
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

I’m seeing a lot of versions of the correct logic under this comment, so here’s mine!

    if((mask & WGPUColorWriteMask_Alpha) && (mask & WGPUColorWriteMask_Blue)) { //… }
This is the least confusing form I’ve seen that doesn’t require a function, macro, custom operator, etc.

Re: Packed structs in Zig make bit/flag sets trivial

#118
post #9
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

Indeed, you would need to check that the mask ends up being exactly alpha and blue, otherwise it's just an automatic boolean conversion from integer to boolean, which many languages are doing away with due to all the bugs it produces.

Yeah, you cant do that in Go, even explicitly:

    // cannot convert i (variable of type int) to type bool
    bool(i)
youd need to use a function:

    func to_bool(i int) bool { return i != 0 }

Re: Packed structs in Zig make bit/flag sets trivial

#119

Earlier quoted context omitted.

> In practice, everything you're likely to come across will be little endian nowadays The internet?

Not really relevant to a discussion about CPUs and compiler implementations...

It's a language design feature that makes some sorts of networking code much easier to write. Why wouldn't that be relevant?

Re: Packed structs in Zig make bit/flag sets trivial

#120
post #62
post #48

Earlier quoted context omitted.

It is not possible to specify bitfields in a way that makes sense, is consistent with a bytewise view of memory, and is portable between big endian and little endian processors. Say you have, for instance (using C notation) struct { unsigned one : 8; unsigned two : 8; }; The fields are supposed to be represented in memory in the same order they are declared, so one is the first byte and two is the second byte. This s…

> It is not possible to specify bitfields in a way that makes sense, is consistent with a bytewise view of memory, and is portable between big endian and little endian processors. I'm not sure I accept "consistency with a bytewise view of memory" as a well-defined, reasonable concept. I do expect to give a list of bit widths, and get a field that has these in consecutive order. Why would it randomly do weird things o…

I agree, if you're changing endian-ness then bitwise compatibility between in-memory formats are out the window by definition. Even if we're just declaring a packed struct containing a single int32_t it's not gonna match at the bit/byte level.

Unless you define a single 'right' bit order and then swizzle/unswizzle every value being written to or read from a packed struct, but then that's becoming more of a serialize/unserialize which is a different thing.

Post reply on HN