Front page | perl.perl5.porters |
Postings from June 2022
Re: A troubling thought - smartmatch reïmagined
Thread Previous
From:
Paul "LeoNerd" Evans
Date:
June 25, 2022 20:24
Subject:
Re: A troubling thought - smartmatch reïmagined
Message ID:
20220625212358.76f1c608@shy.leonerd.org.uk
By way of an addendum, here's an entire additional section I was going
to write in the blog post. It doesn't directly relate to the thoughts
presented there, but it's another perspective on things:
## Comparisons on User-defined Classes
Specifically, lets think about an object type like String::Tagged. In
brief for people not familiar with it, it's an object class that
presents string-like behaviour, but with extra data stored on extents
of the string buffer. For example, it might want to store formatting
information like colours and font-rendering attributes. There's various
subclasses of it for handling HTML, POD, etc...
Right now, it doesn't actually define an `eq` operator, so the usual
fallback logic will apply and just compare the individual characters in
the actual string buffer, ignoring any of the extra (formatting) tags.
E.g.
my $x = String::Tagged->new_tagged( "This is my message",
fg => "red"
);
my $y = String::Tagged->new_tagged( "This is my message",
fg => "green"
);
say "Equal" if $x eq $y;
will claim the two strings are equal. This probably isn't what the user
wants. Probably what should happen is that the String::Tagged class
should provide an overloaded `eq` operator that compares not only that
the string buffers are equal, but also that any additional tags are all
equal as well. Thus, given the above example, the operator would
conclude the instances are not equal, because they have a different
value for the 'fg' tag across the whole range.
This is where the problem starts to become apparent. By what choice of
comparison operator should that nested test operate? In particular,
lets think about the following pair of instances:
my $x = String::Tagged->new_tagged( "message",
fg => "red", weight => "1.0"
);
my $y = String::Tagged->new_tagged( "message",
fg => "red", weight => 1.0
);
It's fairly obvious to the casual human observer that these ought to be
equal, yes? Same string, same set of tags with the same values...
But wait (pardon the phrasing) - what about the value of the 'weight'
tag here? It has the string value "1.0" in the first instance, but the
numerical value 1.0 in the second. A test performed by `==` would
compare these values equal, but by `eq` they would not.
Superficially, the thought might appear that some specific subclass of
String::Tagged, built for a given use-case, might want to provide
metadata about each of its possible tag types, to say how to compare
them; but that has a lot of troubling consequences. Plus it won't work
nicely for ad-hoc uses.
It sortof feels like this is another case where if we had a single
equality-test operator that could better pick its comparison semantics,
it would be much easier to distribute downwards through these objects
without declaring that sort of typing information upfront.
--
Paul "LeoNerd" Evans
leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Thread Previous