Any interest in "flags" (type safety for enumeration bitsets)

Hi all, I wondered if anyone was interested is this idea - it's something I make a lot of use of, so figured it may be useful to others. I'm far from being expert on boost, the STL, or even C++ so it could easily be that this idea is encapsulated elsewhere and I've simply missed it - apologies if this is the case. Also I'm new to the whole contributing to boost thing, so I hope I've not done anything wrong in that respect. Description A class not dissimilar in operation to std::bitset, but specifically for enumeration flags/bitsets (i.e. combinations of enumerations - of a single enum type - or'd together). That is, a simple wrapper class around enumeration based flags - expected to be completely compiled out by any reasonable C++ compiler. Type safety for enumeration bitsets if you like. Motivation The goal is simple, push potential errors from run time, back to compile time. Additionally it should provide better self documenting code, and assist library users in understanding the arguments required and accepted by a function using the code. Take an example from the STL: void fstream::open(const char *_Filename, ios_base::openmode _Mode); which essentially translates to: void fstream::open(const char *_Filename, int _Mode); Meaning that the following code will compile: std::fstream strm; strm.open("file.txt", 666); Although the results will be anybody's guess - and more importantly may change if the library is changed, producing potentially horrid bugs (not something I would relish tracking down). The above example may be somewhat convoluted, but many times I've seen code where flags have been required as an argument, supposed to be from a specific enumeration only for users to use an enumeration of a different kind, or where a flag is required, but a user passes '0' which is not always a valid option. The new class would mean changing the above to: void fstream::open(const char *_Filename, boost::flags<openmode_enum> _Mode); which would result in an error for the given example (since "666" is not a valid openmode_enum enumeration). Any combination of or'd openmode_enums would, however, compile properly (and would behave as if the flags class did not exist). Obviously this is not a full proof solution - it's as easy to circumvent as enumerations themselves, importantly however someone circumventing it has to try - it'd be much more difficult to accidentally break. Anyways - I hope I've gotten the idea across (and that you all like it :o) Cheers for reading - all comments appreciated! Iain

Hello, your library sounds interesting to me, even if I have some questions: 1) what requirements the enumeration type should satisfy? For example, am I obliged to declare 2's powers? such as enum my_enum { flag1 = 1, flag2 = 2, flag3 = 4, ..... }; 2) when you assign a value to a boost::flags<my_enum>, do you use my_enum constants? It seems that flag1 | flag2 is an int, thus how can you distinguish between flag1 | flag2 and another user provided integral constant. Do you overload the "bitwise or" to produce an intermediate object??? 3) I agree with you about the usefulness of such a library, since a compile time check will assure that whenever the code is actually executed, properties will be always in a sensible state (eliminating the annoying and error prone runtime validation). If the programmer consider every notable case, then a static checked flag will give us the same assurances which could give us a collection of methods, one for each particular flag combination. Best regards, Manuel Fiorelli

When you speak about the vulnerability of your library, do you refer to the fact that a cast to enum could be used to avoid the static type check?

your library sounds interesting to me, even if I have some questions:
Glad it's of interest :o) Hope this helps clarify things:
1) what requirements the enumeration type should satisfy? For example, am I obliged to declare 2's powers? such as enum my_enum { flag1 = 1, flag2 = 2, flag3 = 4, ..... };
There would be no requirements as such - although only values that can be sensibly or'd together would make any sense. So normally I'd expect power of two's would be used, but there would be nothing to stop people using non-power of two's. Apart from anything else this would allow people to use bit masks if required (so long as the mask belongs to the enum there is no problem).
2) when you assign a value to a boost::flags<my_enum>, do you use my_enum constants? It seems that flag1 | flag2 is an int, thus how can you distinguish between flag1 | flag2 and another user provided integral constant. Do you overload the "bitwise or" to produce an intermediate object???
Overloading the relevant operators is the idea - although it could create potentially complex statements that result in a lot of temporary objects, I'd hope the compiler would be clever enough to optimise them away. Of course, even if the compiler did not optimise them all away, I would suspect that in most cases it is unlikely to pose a problem. Certainly I'd be surprised to find it causing performance issues.
3) I agree with you about the usefulness of such a library, since a compile time check will assure that whenever the code is actually executed, properties will be always in a sensible state (eliminating the annoying and error prone runtime validation). If the programmer consider every notable case, then a static checked flag will give us the same assurances which could give us a collection of methods, one for each particular flag combination.
The more errors we can push back to the compiler the better!
When you speak about the vulnerability of your library, do you refer to the fact that a cast to enum could be used to avoid the static type check?
Exactly - but if a user is doing that then there is little hope :o) As I said, it's not an ideal solution, but IMO far better than we currently have. Besides, when it's possible to cast a type to any other type there is only so much can be done to protect against bad values. Hope that answers you questions - feel free to ask more! (Or ask again if I've not answered your questions properly.) Iain

Thanks you for the explanation. Also, check that your overloading system doesn't cause any unexpected behavior in components which doesn't use your library. I am a newbie of Boost mailing list: you should wait for answers from more important members. Best regards Manuel Fiorelli
participants (2)
-
iain.denniston@blueyonder.co.uk
-
Manuel Fiorelli