7 ms·
if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like
by arjvik 4y ago
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.
- flohofwoe 4y agoYes it would need to be: if ((mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { ... } ...which is quite a mouthful.
- deleted 4y ago[deleted]
- tempodox 4y agoIn C I'm using a macro for stuff like that (improving readability, avoiding errors). In Zig I could use a `comptime` function, I presume?
- messe 4y agoIt depends on what else you’re doing. In this situation normal function would suffice in either C or Zig.
- chrismorgan 4y agoI’ve definitely desired an operator that combines these before. I’ve settled on &== as the best syntax in C-style languages, with a &== b being equivalent to a & b == b (but with a single evaluation of b). if (mask &== WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) { … } I find only two very minor problems with it: firstly, that it’s not commutative (that is, a &== b is not equivalent to b &== a). Secondly, that it can be confused with the bitwise-and assignment operator &= (a &= b being equivalent to a = a & b for singly-evaluated lvalue a). I’d then add |== for consistency and because it is conceivably useful. ^== is tempting, but since a ^== b would be just another spelling of a == 0, I’d skip it.
- magicalhippo 4y ago> I find only two very minor problems with it: firstly, that it’s not commutative Why is that a problem? That is, if a has additional bits set compared to b, then ((a & b) == b) != ((b & a) == a), no?
- chrismorgan 4y agoOf common operators, / and - are the only ones that aren’t commutative. For equality comparisons, there are two opposing conventions: actual == expected (the more popular, in my experience), and expected == actual (by no means rare). Having &== and |== be order-sensitive (though there’s absolutely no question in my mind about what the ordering should be) is mildly unfortunate. It’s very minor.
- magicalhippo 4y agoYeah ok. I'd consider that just a thing you gotta know. Like how for certain floating point values (a / b) * (c / d) can be fine while (a * c) / (b * d) gives you +/- infinity. It's a separate operator after all, one I also miss a lot...
- beeforpork 4y agoFaszinating: I also thought about exactly '&==' in the past. It seems to be natural choice for this. But then, continuing that thinking, if you have '&==', you'd also need '&!=' -- that looks really confusing. Can't we turn that into a '==0' test somehow? Maybe '^&', because '((a ^ b) & b) == 0' is equivalent to '(a & b) == b'. And, as somehow said: '~&' also works: '(~a & b) == 0' is also equivalent to '(a & b) == b'. if ((a ~& b) == 0) { ... } Wait -- we can swap that into '&~' and we're back in C. However, it reverses the logical order, with the test bits first: if ((b & ~a) == 0) { ... } if (((WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) & ~mask) == 0) { ... } So we're back -- this is standard C now. But I find it incomprehensible.
- chrismorgan 4y ago
- suyjuris 4y agoYou can also do it as follows: if (!(~mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue))) { ... } Not quite as long but perhaps less readable.
- lobo_tuerto 4y agoWhat about? if (mask & WGPUColorWriteMask_Alpha & WGPUColorWriteMask_Blue) { // alpha and blue are set.. }
- ElectricalUnion 4y ago> `mask & WGPUColorWriteMask_Alpha & WGPUColorWriteMask_Blue` If WGPUColorWriteMask_Alpha and WGPUColorWriteMask_Blue doesn't share bits, isn't this garanteed 100% to be false?
- childintime 4y agoI 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.
- tzs 4y agoIf you are willing to assume that the masks each only have 1 bit set, this would be less of a mouthful although it would draw other objections: if (@popCount(mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == 2) I do not know Zig, so the syntax might not be right. I did check to see that it has popcount [1]. If it has some concise way to flip all the bits, then this would be another possibility that isn't too verbose, but might raise other objections. Let fmask be mask with all the bits flipped (how would one do that in Zig?). if ((fmask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == 0) [1] https://ziglang.org/documentation/master/#popCount https://ziglang.org/documentation/master/#popCount
- nurbl 4y agoI think the point of the example is that in zig you'd just do if (mask.alpha and mask.blue) {
- fwsgonzo 4y agoIndeed, 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.
- svnpenn 4y agoYeah, 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 }
- samatman 4y agoSeems a bit mean-spirited to provide casts but not that one.
- svnpenn 4y agonot really. Go has no concept of truthy: https://developer.mozilla.org/docs/Glossary/Truthy https://developer.mozilla.org/docs/Glossary/Truthy and I fully support that decision. If you want to use a boolean, you need to be explicit about it.
- samatman 4y agoA statically typed language shouldn't indulge in truthiness, no. But a cast is isn't truthiness, it's truth: the meaning of "make this int impenetrable to all but truth and falsehood" is in practice well defined, there's nothing implicit happening here. The compiler isn't going to make that function, it's going to optimize back to a cast to boolean. Why make the poor shmoe user type it out?
- svnpenn 4y agoCast int8 to int16 isn't the same thing as int to boolean. In the first case, you get the same number (ignoring wrapping issues). In the second case, you're asking the compiler to make an arbitrary decision about what numbers go to what booleans.
- deleted 4y ago[deleted]
- inhahe 4y ago"WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue" creates a number with both the alpha and blue bits set, then "mask &" (that number) ands the mask with that number in which both bits are set, so it'll only return true if both alpha and blue are set. The parenthetical grouping of the operators is key here. edit: oh, i think i'm wrong, nevermind.
- shultays 4y agoNo it won't. & is "binary and" and result will be WGPUColorWriteMask_Alpha or WGPUColorWriteMask_Blue if only one of them is set. Which is non zero so evaluated to true. So it checks either or those flags Correct usage would be if you want both flags. (flag & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)
- sqrt_1 4y agoI believe it would need to be something like if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) for both bits to be set here.
- flohofwoe 4y agoNo, the expression will resolve to 'true' if any of the Alpha or Blue bits are set.
- jbverschoor 4y agoThat's a 'user error'. "Nothing wrong with the language"
- hurril 4y agoThat's a user error because there very much is something wrong with the language. The error is that it deals in truthy and falsy rather than a strict true^false dichotomy. So 1 is just as truthy as 2 is. And -234123 for that matter.
- bayindirh 4y agoIf that’s user error, then there’s nothing wrong with C, C++, Java, JavaScript and myriad other languages. Then we don’t need any new ones on the basis of readability, elegance, expressiveness and myriad other subjective properties. Yet many discuss these aspects primarily.
- klabb3 4y agoI believe parent was sarcastic and agrees with you.
- jbverschoor 4y agoI have to go to chandler’s sarcasm class. Can I BE any more obvious?
- DecoPerson 4y agoI’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.
- dom96 4y agoThis is why bit sets are far better at this and should be used, i.e.: if WGPUColorWriteMask.Alpha in mask and WGPUColorWriteMask.Blue in mask: ...
- jstimpfle 4y agoYou don't need syntactical sugar. Just write a function. static bool all_bits_set(i32 value, i32 mask) { return (value & mask) == mask; } Here I'm assuming 32-bit values. In C, with relatively little support for generics, you can consider making multiple versions, possibly using _Generic (note, I haven't evaluated the sanity of using _Generic). Alternatively you can use a #define. However, you need to use "mask" twice, so that gets tricky - either it requires care to keep the corresponding expression at the call site side-effect free. Or the macro needs to be written using compiler extensions like statement expressions and typeof() variable declarations à la Linux kernel.
- shaded-enmity 4y agoThe nice thing about this is that it's simple and works pretty much in any language so there's very little cognitive strain if you work with multiple languages at the same time.
- tredre3 4y agoYeah the usual way in C would be to use statement expression (which is a GCC extension but is supported by at least clang and msvc) #define all_bits_set(value, mask) ({__typeof__(value) v = (value), m = (mask); (v & m) == m; }) I personally would go for the extension aboveor a single 64 bit function, but here's the _Generic version: static bool all_bits_set32(i32 value, i32 mask) { return (value & mask) == mask; } static bool all_bits_set64(i64 value, i64 mask) { return (value & mask) == mask; } #define all_bits_set(value, mask) _Generic((value), int32_t: all_bits_set32, int64_t: all_bits_set64)(value, mask)