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

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

Thread Previous | Thread Next
From:
Ricardo Signes
Date:
August 25, 2012 05:07
Subject:
Re: fixing smartmatch just hard enough (and when, too)
Message ID:
20120825120740.GA32435@cancer.codesimply.com

I didn't sleep well last night, and woke up with a sudden sense of uncertainty
about lhs overloading of smartmatching in almost all cases.  I think I didn't
sleep well because my brain was working on this, but it's possible that my
brain thought of this because it didn't sleep well, and it's nuts.  But let's
find out together.

* Damian Conway <damian@conway.org> [2012-08-23T21:08:27]
> Here are six cases where LHS overloading would matter too:
> 
>     1. A lazy string class, which loads text from disk on-demand:
> 
>          if ($lazystring ~~ qr/pattern/) {...}
> 
>          # i.e. want LazyString's overloading, not a regex match against
>          # stringified $lazystring object's address

No, we want the same as C< $lazystring =~ qr/pattern/ >.  That can't be
overloaded now, but if it could, that's what we'd want.

>     2. An interval class:
> 
>         my $reading = Interval->new($raw_data, plus_minus=>$uncertainty);
> 
>         if ($reading ~~ 0) {...}
> 
>         # i.e. want Interval's overloading, not a numeric match against
>         #      $reading object's address

No, we want the same as C< $reading == 0 >, which can be done with current
overloading.  (In fact, which is done in my own Number::Tolerant for just this
means.)

>     3. A query-result class, which encapsulates the outcome of a
>        database lookup:
> 
>         my $result = $db->find($query);
> 
>         if ($result ~~ 'camel') {...}
> 
>         # i.e. want QueryResult's overloading, not string match against
>         #      $result object's address

No.  Either we're passing the $result to a hunk of code that expects C< $x ~~
'camel'> to act like `eq` or we're not passing the $result anywhere and we can
write a more special-cased dispatch that knows it can call $result->matches

>     4. An iterator object:
> 
>         my $iter = get_iterator_over($data_structure);
> 
>         until ($iter ~~ undef) {
>             ...
>         }
> 
>         # i.e. want Iterator's overloading, not definedness match against
>         #      $iter object's address


  if (defined $var and $var ~~ undef) {
    $rjbs->will( 'cry cry cry' );
  }

>     5. A DNA sequence object:
> 
>         if ($dna_sequence ~~ qr/GATTACA/) {...}
> 
>         # i.e. want DNASeq's overloading, not regex match against
>         #      $dna_sequence object's address

This is just #1.

>     6. Prototyping a smarter dualvar with a Chip-like memory of its origins:
> 
>         my $dv_n = SmartDualVar->new(0)
>         my $dv_s = SmartDualVar->new("zero");
> 
>         say $dv_n;
>         say 0+$dv_s;
> 
>         if ($dv_n ~~ 0)      {...}     # succeeds
>         if ($dv_s ~~ 0)      {...}     # fails
> 
>         # i.e. want SmartDualVar's overloading, not numeric matches
>         #      against the $dv_n and $dv_s object's addresses

Does C< $dv_s == 0 >?  If so, I think the smart match should also succeed.

> In other words, every single time an object is the LHS operand of a
> smartmatch, we need (at least the option) to be able to have that object
> decide how the match should work.

I soundly disagree.

Every single time the user writes C< $a ~~ "string literal" > we need it to be
equivalent to using eq.  Otherwise, I see this future:

  "Well, I used to use `when(4)` here, but it turned out that sometimes I was
  getting an object that didn't handle being on the lhs of the smart match
  correctly, so now I write `when { $_ == 4 }`"

...and then we're back to me cry cry crying.

David Golden said that "smart matching" was "generic matching."  The behaviors
you suggested above were not always generic.  If you know you've got special
data, you should give it a method and there you go.

In every case of the dispatch table, the kind of overloading required for the
lhs is clear:

     $b      | equivalent to     | $a should overload
     --------+-------------------+-----------------------------------------
  1. CodeRef | $b->($a)          | nothing; can't be done
  2. Object  | $b->somecode($a)  | nothing; can't be done
  3. Regex   | $a =~ $b          | "" (for now)
  4. String  | $a eq $b          | eq
  5. Number  | $a == $b          | ==

Cases (1) and (2) most clearly demonstrate the problem to me.  It means these
two things will not be equivalent:

  if (sub { return }->($x)) { ... }
  if ($x ~~ sub { return }) { ... }

This seems like complete madness.

(As an aside, I imagine what I might do is this:

  my $object = acquire_object;
  given ($object->matcher) {
    when (...) { ... }
    when (...) { ... }
    when {...} { ... }
  }

There, I can avoid putting goofy overloads for eq and =~ on the object, but
return a proxy that implements them.  I still get a nice "compute once" and the
compactness of given/when, but we've established that we're working with a
particular kind of object.  But this idea is definitely less slept-upon than
the rest of this post.)

-- 
rjbs

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