6 comments

[ 2.8 ms ] story [ 26.0 ms ] thread
Raku has this feature by design. While there technically is a general equality operator `eqv`, you rarely see it used. Instead, you use the matching operator, `~~`, which can check equality, or check if a string matches a regex, or check if a number is contained within a range, etc.
The operator is called "smart-match".

When you do:

    $a ~~ $b
You are in fact doing:

    $b.ACCEPTS($a)
So any object can determine how it will interpret any other object in smart-matching. The core classes or course have all these methods implemented in the expected way. And you can easily do that for your own classes as well:

    class Foo {
        multi method ACCEPTS(Int:D $count) { $count == 42 }
        multi method ACCEPTS("frobnicate" --> True) { }
    }
    my $foo = Foo.new;
    say 42 ~~ $foo;            # True
    say 666 ~~ $foo;           # False
    say "what" ~~ $foo;        # False
    say "frobnicate" ~~ $foo;  # True

    assert user_data == {
        'id': IsPositiveInt,
        'avatar_file': IsStr(regex=r'/[a-z0-9\-]{10}/example\.png'),
> Without dirty-equals, you'd have to compare individual fields and/or modify some fields before comparison ...

Hmm, I'm not convinced. Why not

    assert dirty_check(user_data, {
        'id': IsPositiveInt,
        'avatar_file': IsStr(regex=r'/[a-z0-9\-]{10}/example\.png'),
It would work just as well without abusing the == operator. Doing so seems like a bit of a gimmick (although the actual functionality of the library looks useful).

Edit: Ah, I guess the difference is that dict.__eq__ (and list.__eq__ and so on) recursively tests equality of all child elements. So to support arbitrary nesting I think it really does have to be the equals operator.

I disagree, this is much less clear. It also don't work well with pytest's error output.
And it would be much more complex to implement, particularly with recursively nested types.