My question is related to user defined function in set operations, but I think I can cut to the core of the problem:
How do I choose a specific hashing function? For example, if I want to do value-based matching rather than reference-matching, and I want to see whether a certain tuple is present (or simply delete it):
my %data := SetHash.new: (1, 2), (3, 4);
%data{$(1, 2)}:delete; # False
In C++ or C#, I could give a custom hashing/comparison function to the constructor. In C#, hashing by value will automatically happen if my data type is a struct
(a value-type rather than a reference-type). Perl 6 does value-type hashing to some extent for Pair
(if the Pair doesn't contain any containers), but I don't see how to make it work for any other complex type.
On one hand, I get why this isn't the safest operation--it's easy to define objects whose hash code can change after they've been inserted. But that hasn't stopped .NET and the C++ STL from allowing custom hashing.
A possible API usage (with the chained hashing logic inspired by this, originally from Boost) would be:
class MyHasher does Hasher of Array[Int] {
method get-hash-value(Int @array) {
reduce
-> $a, $b {$a +^ ($b + 0x9e3779b97f4a7c16 + ($a +< 6) + ($a +> 2))},
0,
|@array;
}
method equals(Int @a, Int @b) { @a eqv @b; }
}
my %data := SetHash.new(
my Int @=[1, 2], my Int @=[3, 4],
:hasher(MyHasher.new)
);
say %data{$[1, 2]}; # should be True
And this would be the hasher role, which should be provided by the Perl 6's core library, if it doesn't already exist:
role Hasher[::T=Any] { method equals(T $a, T $b --> Bool) { ... }; method get-hash-value(T $obj) { ... } }
Solution: At present, the most reasonable solution is to override a class's .WHICH
method, which serves as a hash value and is used for equality testing. I gave an example of a hash-key class which emulates a value-type here. It's almost as versatile as a custom hash function per hash object, since the key type can be declared when the hash is created. (This can't be done for Set
since Set
isn't parameterized.)