On my quest to a concurrent File::Find I found the need to have arguments (in this case as Bool) that are of a group of sorts and are mutual exclusive. Enums are very groupy, introduce easy to use names into the scope (directly or via is export ) and should be easy to make mutual exclusive. The easy part was a bit naive because typed slurpy arguments are not supported (yet). If there is no easy way, there must be a hard way that is possible.

First let’s define two enums that serve as options to find.

package Find { enum Type (<File Dir Symlink>); enum Options (<Recursive Keep-going>); }

Now we can have a where-clause that first checks if all members of a slurpy array are either of type Find::Type or Find::Options. Then we can check how many elements of Find::Options there are. Since there can be only one we complain about exclusiveness if there are to many.

+@options where { @options.all (elem) (Find::Type::.values (|) Find::Options::.values) && (+(@options.grep: * ~~ Find::Type) <= 1 or die "can only check for one type at a time") }

In the body of the routine we can use junctions and smart matching to check if options are present.

my Bool $recursive = any(@options) ~~ Find::Recursive; my %tests = Find::File => {so .f}, Find::Dir => {so .d}, Find::Symlink => {so .l}; @tests.append(%tests{@options.grep: * ~~ Find::Type});

The routine is then called with a list of flags at the end of it’s parameter list.

find(%*ENV<HOME>, include => {.extension eq 'txt'}, exclude => ['cfg', /.xml $/] , Find::File, Find::Recursive, Find::Keep-going);

The same would be possible to do with named arguments but I can’t see a way to do the exclusiveness in a where-clause. I like to have as much argument processing in the signature because it makes it easy to write documentation. Separate all arguments with a newline and then translate type constraints and where-clauses into plain English. Also, having enums as flags feels quite 6-ish and that’s what this blog (post) is about.