[Library idea] Type-safe Flagsets

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

[Library idea] Type-safe Flagsets

Boost - Dev mailing list
Hello everybody,

I want to know if some people are interested in a type-safe flagsets. I
define flagsets as a container similar to a bitset, but where each bit has
a meaning.

For example, we could have in some game :

    enum Direction : unsigned {
        UP    = 0b0001,
        DOWN  = 0b0010,
        LEFT  = 0b0100,
        RIGHT = 0b1000
    };
    ...
    unsigned player_dir = UP | RIGHT;
    if ((player_dir & (UP|LEFT)) == (UP|LEFT))
        player.setAnim("up_left");
    player_dir &= ~UP; //removing UP from player_dir

I think there are some issues with this kind of flagset :
- you need to think about power-of-twos when attributing values to your
flags.
- you need to use bitwise operations which can be non-trivial, even for
removing only one flag.
- it is not safe:
    for example with another flagset using the flag INIT_VIDEO (in a window
library like SDL),
    you can do " UP | INIT_VIDEO " even if the two flagsets have nothing in
common

With a type-safe flagset library, this code would become :

    namespace Direction {
        struct UP;
        struct DOWN;
        struct LEFT;
        struct RIGHT;
        using Type = flagset<unsigned, UP, DOWN, LEFT, RIGHT>;
//unsigned is the underlying type
    };
    ...
    auto player_dir = Direction::Type::Value<Direction::UP, Direction::RIGHT>();
    if (player_dir.allOf<Direction::UP,Direction::LEFT>())
        player.setAnim("up_left");
    player_dir.reset<Direction::UP>();


It is more verbose but also more safe and easy to use.

I actually have a partial implementation on GitHub, supporting read, write
and conversions to strings : https://github.com/J-Vernay/flagset

I would like to know if some people are interested in this kind of library,
and if yes, what they think about the current syntax/implementation.

Thanks for reading !

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
On 25/06/2018 06:43, Julien Vernay wrote:

> I think there are some issues with this kind of flagset :
> - you need to think about power-of-twos when attributing values to your
> flags.
> - you need to use bitwise operations which can be non-trivial, even for
> removing only one flag.
> - it is not safe:
>      for example with another flagset using the flag INIT_VIDEO (in a window
> library like SDL),
>      you can do " UP | INIT_VIDEO " even if the two flagsets have nothing in
> common

Note that C++11's scoped enums solve those safety issues.

And if you don't care about the specific bit values (eg. you don't need
to directly serialize the value or interoperate with an external API),
then you can use bitfields, which resolve all of those issues (albeit
with other limitations).


Does your approach allow you to predefine standard combinations of flags
(eg. defining UP_LEFT = UP | LEFT)?  That's a common requirement for
these sorts of things.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
The aim is that each flag is independent, so you can have two flags active
at a same time, while an enum should have only one value at a time.
Scoped enums do not solve those issues because they can not be combined, if
you want to combine them you first need to used "static_cast" for
converting it to an int, then using & | ^ to combine them.

For predefining standard combination of flags, as UP_LEFT, you can do :

    constexpr auto UP_LEFT =
Direction::Type::Value<Direction::UP,Direction::LEFT>();

Thanks for your answer !

2018-06-25 2:47 GMT+02:00 Gavin Lambert via Boost <[hidden email]>:

> On 25/06/2018 06:43, Julien Vernay wrote:
>
>> I think there are some issues with this kind of flagset :
>> - you need to think about power-of-twos when attributing values to your
>> flags.
>> - you need to use bitwise operations which can be non-trivial, even for
>> removing only one flag.
>> - it is not safe:
>>      for example with another flagset using the flag INIT_VIDEO (in a
>> window
>> library like SDL),
>>      you can do " UP | INIT_VIDEO " even if the two flagsets have nothing
>> in
>> common
>>
>
> Note that C++11's scoped enums solve those safety issues.
>
> And if you don't care about the specific bit values (eg. you don't need to
> directly serialize the value or interoperate with an external API), then
> you can use bitfields, which resolve all of those issues (albeit with other
> limitations).
>
>
> Does your approach allow you to predefine standard combinations of flags
> (eg. defining UP_LEFT = UP | LEFT)?  That's a common requirement for these
> sorts of things.
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman
> /listinfo.cgi/boost
>

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
On 25/06/2018 18:09, Julien Vernay wrote:
> The aim is that each flag is independent, so you can have two flags active
> at a same time, while an enum should have only one value at a time.
> Scoped enums do not solve those issues because they can not be combined, if
> you want to combine them you first need to used "static_cast" for
> converting it to an int, then using & | ^ to combine them.

For that, I like the approach in this answer:
   https://softwareengineering.stackexchange.com/a/338472/303655

Where you use a standard (non-power-of-two) enum to define the bit
positions, and a separate class that turns it into a bitset.


If you do want to explicitly define the power-of-two values, then you
can use something like this instead:
   https://github.com/grisumbras/enum-flags


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Did you (or would you) consider to provide other 'concepts', like
triboolsets (trits) (indeterminate values) or floating point values, the
latter for example expressing closeness or energy levels?

degski
--
*"If something cannot go on forever, it will stop" - Herbert Stein*

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
>
> For that, I like the approach in this answer:
>   https://softwareengineering.stackexchange.com/a/338472/303655
>
indeed it is a good approach, is there a reason why something similar to
this is not part of Boost ?

Did you (or would you) consider to provide other 'concepts', like
> triboolsets (trits) (indeterminate values) or floating point values
>
 Triboolsets could be a possibility (even if not sure of the purpose), but
providing other concepts as floating point or int is too specific to an
application and I think it should have its own type.

2018-06-26 7:21 GMT+02:00 degski via Boost <[hidden email]>:

> Did you (or would you) consider to provide other 'concepts', like
> triboolsets (trits) (indeterminate values) or floating point values, the
> latter for example expressing closeness or energy levels?
>
> degski
> --
> *"If something cannot go on forever, it will stop" - Herbert Stein*
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/
> mailman/listinfo.cgi/boost
>

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
On 26 June 2018 at 16:15, Julien Vernay via Boost <[hidden email]>
wrote:

>  Triboolsets could be a possibility (even if not sure of the purpose) ...
>

One could use them for something like G.O.A.P.
<https://github.com/stolk/GPGOAP>


> ... but providing other concepts as floating point or int is too specific
> to an
> application and I think it should have its own type.
>

Once one has adopted the idea of "flags" to possibly not exist, i.e. not to
be either true or false, a natural extension is to adopt "fuzzy flags" as
well, i.e. use floats. Some bike-shedding: I think the word flags is not
sufficiently general.

degski
--
*"If something cannot go on forever, it will stop" - Herbert Stein*

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
On 27/06/2018 01:41, degski wrote:
> Once one has adopted the idea of "flags" to possibly not exist, i.e. not to
> be either true or false, a natural extension is to adopt "fuzzy flags" as
> well, i.e. use floats. Some bike-shedding: I think the word flags is not
> sufficiently general.

At this point you've sufficiently departed the "bitwise operations"
model to make it fairly meaningless.  You'd probably be better served
with a regular structure or with Boost.ProgramOptions instead.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [Library idea] Type-safe Flagsets

Boost - Dev mailing list
On 27 June 2018 at 02:37, Gavin Lambert via Boost <[hidden email]>
wrote:

> On 27/06/2018 01:41, degski wrote:
>
>> Once one has adopted the idea of "flags" to possibly not exist, i.e. not
>> to
>> be either true or false, a natural extension is to adopt "fuzzy flags" as
>> well, i.e. use floats. Some bike-shedding: I think the word flags is not
>> sufficiently general.
>>
>
> At this point you've sufficiently departed the "bitwise operations" model
> to make it fairly meaningless.


 You would implement trits with bitwise operations using BCT (Binary Coded
Ternary: implementation
<http://homepage.divms.uiowa.edu/~jones/ternary/libtern.shtml>). Ternaries
have some interesting mathematical properties as well, which is explained
here <https://en.wikipedia.org/wiki/Redundant_binary_representation>. There
are also pratical applications
<https://en.wikipedia.org/w/index.php?title=Ternary_numeral_system&action=edit&section=4>.


You'd probably be better served with a regular structure or with
> Boost.ProgramOptions instead.


Did you read the G.O.A.P. link I posted (here's one from MIT
<http://alumni.media.mit.edu/%7Ejorkin/goap.html>)? Because if you had, you
would not suggest to solve this problem with Boost.ProgramOptions.

As to the fuzzy idea, bits are not necessarily digital, think analog
computers.

Personally, I think the flags proposal is an instance of over-engineering
and is making things that are fairly simple (and why not use bitfields, the
compiler does the work, certainly better than any had-coded solution)
complicated. It is also a well-known and understood idea.


degski

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost