lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 2013-07-10 5:14 AM, "Philipp Janda" <siffiejoe@gmx.net> wrote:
>
> Am 09.07.2013 23:54 schröbte Lorenzo Donati:
>
>>
>> I must agree with you. Although I don't need bitops so much, I find them
>> useful from time to time. What I really hate is functional notation for
>> them: any time you try to do little-more-than-trivial stuff you end up
>> with ugly code (from a readability POV).
>>
>> Infix notation is really a must for writing readable, straightforward
>> code using bitops IMHO. I'm not particularly fond of C-like operators,
>> so I wouldn't object to a more luaish keywords-based approach. Moreover
>> you cannot have exactly the same operators as in C, since ^ is already
>> taken,
>
>
> `^` is only taken for numbers, but IMHO it doesn't make much sense to define bit operations on numbers anyway: "Let's take the number of apples and xor it with the number of oranges, right shift by the number of baskets, and we get: total nonsense"! Usually one does arithmetic _xor_ bit manipulation at any given time[*].
> So my suggestion would be: Add a bunch of operators (C-like; if you are going to write C code in Lua, it should look familiar to C programmers; also: most obvious candidates for keyword operators are already taken by bit32) and metamethods, but don't define those for any builtin datatypes. Instead provide a library that implements bitstrings as userdata using those new metamethods. Added bonus: you can define bitstrings of arbitrary length, independent of the size of the integer datatype.
>
>   [*]: The one exception I can think of is implementing hash tables, where most algorithms do extensive bit fiddling to generate "unexpected" bit patterns and the result is a bucket index (i.e. a genuine number). Fortunately we already have those in Lua ...
>
>
> > On 09/07/2013 20.23, Ico wrote:
> >>
> >>    val = val & ~mask
> >>
> >> for clearing bits in a word. Doing this with bit32 does not result in
> >> code that is more readable, IMHO:
> >>
> >>    val = bit32.band(val, bit32.bnot(mask))
> >>
>
> I usually use `val = val - mask` for this, meaning "clear all bits set in mask from val". I also use `a + b` for `a | b`, and `a( b )` for `!(b & ~a)` (i.e.: check if the set of one-bits in b is a subset of one-bits in a). Together with `==` this is enough to implement the common bit flags in C APIs.
>
>
> Philipp
>
These aren't the same though. Addition and subtraction will give incorrect results if not all bits are clear/set. This can be an issue with flags:

FLAG_FOO = 1
FLAG_BAR = 2
FLAG_BAZ = 5 -- FLAG_FOO needs to also be set for this option, so this value sets both

Flags = FLAG_FOO + FLAG_BAZ -- not realizing the redundancy, a programmer sets both flags. This would be harmless (and maybe intentional to improve readability) with |, but produces the wrong result with +.
And perhaps elsewhere in the code:
Flags = Flags - FLAG_BAR -- ensure FLAG_BAR is not set. Again if it already wasn't, this is harmless when using & and ~, but produces the wrong result using -.

These might seem like contrived examples, but it's very common in real code to set multiple flags not knowing some are redundant (or knowing, but wanting to make your intent clear), set flags that may already be set, and clear flags that may already be clear. (Plus, bitflags are only one use of binary operations; they're also commonly used to combine or extract values when multiple fields are packed into a few bytes.)