Is there a way to overload the regex binding operator `=~` in Perl?

Tag: regex , perl , operator-overloading , overloading Author: kuwan17 Date: 2010-08-28

I am working on a small DSL that uses the nomethod fallback for overloading to capture the operators used on the overloaded values. This is similar to the function of the symbolic calculator described in overload's documentation.

This works fine for the standard comparison operators, but consider the following:

my $ret = $overloaded =~ /regex/;

In this case, nomethod gets called to stringify $overloaded, and after that the overloading is lost. I thought about returning a tied variable, which will at least let me carry around the original overloaded object, but that will still get lost during the execution of the regex.

So, the ultimate question is if there is any way to extend overload's idea of a symbolic calculator to include the regex binding operators =~ and !~, so that the above code sample would call nomethod with ($overloaded, qr/regex/, 0, '=~') or something similar?

I also briefly looked into overloading the smartmatch operator ~~ but that didn't seem to do the trick either (always defaults to regex matching rather than overloading).

Edit: I looked into ~~ more, and found that my $ret = $overloaded ~~ q/regex/ works due to smartmatching rules. Close, but not an ideal solution, and I would like it to work pre 5.10, so I welcome other answers.

I guess supplying a wrapper to the regex engine wouldn't work either if you want it to work prior to 5.10.
End the madness! Learn Python!
@bukzor: I'm pretty sure you can't overload the regex binding operator in Python, since it doesn't have one. Of course, you could write a class that would give you similar, limited functionality: code.activestate.com/recipes/…
@Adam => and of course the same can be done in perl. I have been considering making the normally senseless case of $overloaded == qr/.../ behave the same way as $overloaded =~ /.../. That at least will work pre 5.10...

Other Answer1

I feel as though DSLs are best written with source filters in perl. You can literally do ANYTHING you want. ;-) In your example, you can regex replace FOO =~ BAR with myfunc(FOO, BAR) and run arbitrary code.

Here's an example solution:

# THE "MyLang" SOURCE FILTER
package MyLang;
use strict;
use warnings;
use Filter::Util::Call;

sub import {
    my ($type, @args) = @_;
    my %p = @args;
    no strict 'refs';
    my $caller = caller;
    # Create the function to call
    *{"${caller}::_mylang_defaultmethod"} = sub {
        my ($a, $op, $b) = @_;
        $p{nomethod}->($a, $b, 0, $op);
    };
    my ($ref) = [];
    filter_add(bless $ref);
}

sub filter {
    my ($self) = @_;
    my ($status);
    if ($status = filter_read() > 0) {
        $_ =~ s/([^=]+)(=~)([^;]+)/ _mylang_defaultmethod($1,'$2',$3)/g;
    }
    $status;
}

1;

EXAMPLE USE

use MyLang nomethod => \&mywrap;

my $a = "foo";
my $b = "bar";
$x = $a =~ $b;

sub mywrap {
   my ($a, $b, $inv, $op) = @_;
   print "$a\n";
}

Now the above will print "foo\n" since it's what is in the "$a" variable. Of course you may want to do some slightly more intelligent parsing for the regex replacement in the filter, but this is a simple proof of concept.

comments:

Why the downvote?
because you suck at ping pong
Probably because in general, source filters are a fragile solution, especially when the filter has context-sensitive boundaries. Your example works in the case of $x = $a =~ $b, but will fail with $x = myfunc $a =~ $b. There are just too many corner cases for such source filters to ever be truly robust. In addition, if you do attempt to write a source filter, you should at least use Filter::Simple with the code_no_comments modifier so that you are only filtering codelike areas, and not comments, pod, or quoted strings.
Also, in general, you should avoid lexicalizing the variables $a and $b because once lexical, any calls to sort in that scope will die.
All that may be true, but he's the only one who's actually answered the question. If the only way to do this is through source filters, that's useful unformation. I concede, though, that it's mainly useful in that if you can only do it with source filters, maybe you should try to simply live without it. ;)