Home > Perl6 > Are these your keys?

Are these your keys?

One bug that keeps biting me are typos in constant Hash keys. It’s not hard to confine keys to a given list of strings by mixin a role that overloads method AT-KEY. But that would be a runtime error and replacing one runtime error with another ain’t now good.

Enums do have a constant set of Keys and provide identity a Hash can use. Perl 6 does allow enums as key constraints and will complain at compile time if we ask for a keys that is not defined as a enum key. However, if we confine a Hash to a given set of keys, we may want to output all possible keys, not just the keys that have values associated. We can solve that by mixin in a role.

enum Noms(<Greenstuff Walkingstuff Syntetics>);
(my %eaten{Noms} is default(0)) does role :: {
method keys { Noms::.values }
method kv { gather for self.keys -> \k { take k, self.{k}} }
};
%eaten{Greenstuff}++;
dd %eaten;
# Hash[Any,Noms]+{<anon|75781152>} %eaten = (my Any %{Noms} = Noms::Greenstuff => 1)
dd %eaten.keyof;
# Noms
dd %eaten.keys;
# (Noms::Walkingstuff, Noms::Greenstuff, Noms::Syntetics).Seq
dd %eaten.kv;
# ((Noms::Walkingstuff, 0), (Noms::Greenstuff, 1), (Noms::Syntetics, 0)).Seq

The default value of 0 makes sense for a simple counting Hash. A Failure may be more appropriate for a undefined value, given that we nailed the keys down.

Of cause we can stick those methods into a properly named role and while we are on it, take care about Arrays too. The default value type for enums are Int that start at 0, what is to the liking of Arrays.

role Enumkeys[::T] {
method keys { T::.values }
  multi method kv(Positional:D) { gather for self.keys -> \k { take k, self.[k] } }
  multi method kv(Associative:D) { gather for self.keys -> \k { take k, self.{k} } }
}

If we do use a limited set of keys, we should limit the size of the Array to the number of enum keys.

multi sub prefix:<+>(Any:U \E where .HOW ~~ Metamodel::EnumHOW){ E.enums.elems }

Since Arrays don’t really have have a key value, Perl 6 won’t help use if we use the Array without enum keys but simple typos will be caught at compile time. Also, we need to do a runtime mixin, that’s where the parentheses around the my-statement come from.

(my @eaten[+Noms]) does Enumkeys[Noms];
@eaten[Syntetics]++;
dd @eaten.kv;
# (Noms::Walkingstuff, Any, Noms::Greenstuff, Any, Noms::Syntetics, 1).Seq

Perl 6 gets use closer to correct programs, one key at a time.

UPDATE: With commit/fef3655 Array shapes understand enums directly, the prefix:<+> is therefor not required anymore. (That’s less then 24h  reaction time on a bug that wasn’t even reported :)

Categories: Perl6
  1. liztormato
    September 21, 2016 at 23:18

    Great post!

    I wonder if we shouldn’t just handle using an Enum for @a[] be handled by the core. So we wouldn’t need to add a prefix: candidate with a where clause (which could have performance implications).

  1. September 26, 2016 at 23:05

Leave a comment