develooper Front page | perl.perl5.porters | Postings from August 2012

Re: fixing smartmatch just hard enough (and when, too)

Thread Previous | Thread Next
From:
David Golden
Date:
August 23, 2012 18:26
Subject:
Re: fixing smartmatch just hard enough (and when, too)
Message ID:
CAOeq1c_JM2OZptFMX6D=61Nc04heyiAu8sMZniAse51+zt-6ew@mail.gmail.com
On Thu, Aug 23, 2012 at 7:53 PM, Damian Conway <damian@conway.org> wrote:

> The argument for the ordering I've proposed to prefer the RHS object's
> ~~-overloading is that every other (non-overloaded) case in the
> smartmatch table dispatches solely on the RHS type. So, for consistency
> and predictability of *use*, I believe overloaded ~~ should favour the
> RHS object's overloading (if any) and fallback to the LHS object's
> overloading only if necessary.
>

But the semantics of LHS and RHS are different because smartmatch is
non-commutative.

For a LHS object, the only semantically correct thing to do is to transform
one's own value and smartmatch it against the RHS comparator (or possibly a
suitable transformation of it [1]).

For a RHS object, there is no clear meaning for what it means to match,
therefore it's free to do any sort of comparison to the LHS value, which
may or may not involve smartmatching and may or may not invoke the
smartmatch overload on the LHS.

Let's take as an example an Error class whose objects have both a string
and a numerical value.  (Let's assume that it's not *actually* a dualvar,
since that's a different Pandora's box.)  The class overloads q{0+} and
q{""}.  The author overloads ~~ to always smartmatch as a number.

Imagine another class, which implements a length smartmatch, meaning that
~~ is overridden to check if the length of the LHS is greater than some
limit set in the constructor.  E.g. <<$max_length = Length::Max->(8) >>

Then consider:

    $error ~~ $max_length

If the LHS overload is processed first, the numeric value gets smartmatched
against the RHS, which does a length check of the numeric value against the
limit and we effectively get this:

    length($error->number) > $limit

If the RHS overload is processed first, the LHS gets checked for length,
which triggers stringification of the LHS (and thus the q{""} overload) and
we effectively get this:

    length($error->string) > $limit

Avoiding that requires the RHS overload to implement its logic in a
subroutine and smartmatch the LHS against the subroutine (or something
equally clever), thus triggering LHS smartmatch logic and we effectively
get this:

    sub { length(shift) > $limit } -> ( $error->number )

Whatever it does, it *must* give the LHS a chance to trigger its smartmatch
overloading.  (Requiring a subroutine is also inefficient.)

Thus, since a proper RHS overload must trigger a LHS overload anyway, then
the LHS override should trigger first, which simplifies the operation of
RHS overloading.

David

[1] The "problem" with LHS overloading is that the RHS gets passed in a
variable and if we can't tell whether that was originally a number or a
string, we don't know whether to smartmatch a scalar RHS as 0+$rhs or
"$rhs".  But if the LHS knows it should match as string or number, then it
can force that onto a simple RHS scalar value and wind up doing the right
thing.

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About