On Sun, 05 Apr 2020, Joseph Brenner wrote:
> I find in Raku that (as expected) I can use an object as a hash key:
> 
>     class Rutabaga { method color { say "purple (and white)"; } }
> 
>     my $obj = Rutabaga.new
>     my %vegeout;
>     %vegeout{ $obj } = "this works";
> 
> And for something I was doing I wanted to save up
> data about matches for various different regexs,
> so I thought I could just use a hash for this, like so:
> 
>     my (%match_locs, $loc);
> 
>     my $godzilla_rx  = rx:i{ << godzilla >> };
>     if $text ~~ m/$godzilla_rx/ {
>         $loc = $/.from;
>         say "Godzilla: Found at $loc!";
>         %match_locs{ $godzilla_rx } = $loc;
>     }
> 
> But using a regex object as a hash key evidently doesn't work,
> it gives you the warning message:
> 
>    #  Regex object coerced to string (please use .gist or .perl to do that)
> 
> And what's worse is it coerces to an *empty list* which means *every*
> regex is treated as the same key.
> 
> If you I follow the advice to use the *.perl, then that works, of course:
> 
>         %match_locs{ $godzilla_rx.perl } = $loc;
> 
> But you wouldn't be able to use the keys of the hash as a regex
> object later, which seems sub-optimal, though not a concern for
> my present purposes.

The same thing happened with your Rutabaga object. It had a default
Str method that was called when you used it as a hash key. It didn't
really store the object in the key but just its .Str:

  %vegeout.keys.any ~~ Rutabaga;  # OUTPUT: «False»
  %vegeout.keys.all ~~ Str;       # OUTPUT: «True»
  %vegeout.keys[0] === $obj;      # OUTPUT: «False»

This is because Hash objects, by default, have Str(Any) keys, meaning
Str and coercing when required. If you want a Hash which allows any
kind of object as key, you have to declare it such:

  my $obj = Rutabaga.new;
  my %vegeout{Any};  # <-- see: 
https://docs.raku.org/language/hashmap#Non-string_keys_(object_hash)
  %vegeout{$obj} = "this works";
  %vegeout.keys.all ~~ Rutabaga;  # OUTPUT: «True»
  %vegeout.keys[0] === $obj;      # OUTPUT: «True»

This will also work with Regex objects.

Regards,
Tobias

-- 
"There's an old saying: Don't change anything... ever!" -- Mr. Monk

Reply via email to