An issue came up in a class I was teaching today...

There doesn't seem to be an easy way to create a type that allows a set
of enumerated bit-flags *and* all the combinations of those flags...and
nothing else.

For example:

     enum Permissions ( Read => 0b0001, Write => 0b0010, Exec => 0b0100 );

     my Permissions $rwx = Read +| Write;    # Error


I know I could use junctions:

    subset BitFlag where Read|Write|Exec;

    my BitFlag $rwx = Read | Write;

but it's not easy to recover the actual bitpattern from that, except with:

    $bitpattern = [+|] $rwx.eigenstates;

which is suboptimal in readability (not to mention that it requires
MONKEY_TYPING to allow access to the .eigenstates method).


Ideally, what I'd like to be able to do is something like:

    enum Permissions is bitset < Read Write Exec >;

    # The 'is bitset' starts numbering at 0b0001 (instead of the usual zero)
    # and doubles each subsequent enumeration value (instead of the usual ++).
    # It also implicitly fills in the various other bitwise-or permutations
    # as valid-but-nameless enumerated values

    my Permissions $rwx = Read +| Write;    # Now fine


The closest I can think of at the moment is something like:

    enum NamedPermissions ( Read => 0b0001, Write => 0b0010, Exec => 0b0100 );

    subset Permissions of Int where 0 .. [+|]NamedPermissions.enums.values;

    my Permissions $rwx = Read +| Write;    # Fine

which is still a little too constructive, too explicit (you have to get the
bit values right), as well as being too obscure for such a common task.


Of course, I could always create a macro to encapsulate the explicit
constructive obscurity:

    macro bitset ($typename, @value_names)
        is parsed(/:s (<ident>) '<' ( <ident> )+ '>' /)
    {
        # [build code to implement the above trick here]
    }

    # and later...

    bitset Permissions < Read Write Exec >;

but this is such a common requirement in engineering applications that it
would be great if this wheel didn't constantly have to be reinvented.


If anyone can think of a cleaner way to do it within the current semantics,
I'd be very happy to hear of it. I'm jetlagged and bleary from a full day of
teaching and I may well be missing an obvious answer.

Thanks,

Damian

Reply via email to