I was thinking about regular expressions and hypotheticals again this
weekend, and something was bothering me quite a lot. How do rules create
hypotheticals?

Since a rule behaves like a closure, I can see how it could gain access
to existing lexicals, if it's declared inside of the same scope:

    my $x = 1;
    / $x /;

Good so far, now we change said lexical:

    my $x = 1;
    / $x := (2) /;

Ok, got that. Now what about lexicals that aren't declared:

    / $x := (2) /;

This bothers me. Yes, I can see how you could do it via %MY:: or however
that's spelled (I'm typing this in a Vermont B&B, so I can't quite go
check A2), but opening up the stack of my caller and mucking around with
their contents seems rather rude. As Pink Floyd once said, "get your
hands off of my stack!"

So, here's an immodest proposal for kinder and gentler stack mucking.
Essentially, these lexicals are out-of-band return values, and Perl 6
already has a mechanism for out-of-band return information: properties.
When you look at it like this, what you want to do is "throw" these
lexicals up the stack to your caller and let them do the right thing
with them. Here's a non-regexp version of what I'm describing:

    sub a {
        my $x = 1;
        b();
        print "x=$x y=$y\n";
    }
    sub b {
        my $x = 2;
        my $y = 3;
        return undef but lexicals(x=>$x, y=>$y);
    }

This has an unfortunate consequence: The existing lexical C<$x> gets
stomped with the new value of 2. While this might be what you wanted in
some cases, it's probably not a very good idea to allow it in general.
So, lets say that that would generate a warning (error?), and in order
to allow it, you would have to associate a property with your existing
lexical:

    my $x is volatile = 1;

I stole this property name from C, where it means that the variable's
value might be stomped by some external side-effect, which is exactly
what it means here. Every subroutine invocation would have to check
return values for a lexicals property and instantiate any variables as
needed. Variables created this way would be considered volatile so that:

        b(); b();

Would not generate warnings or errors about stomping the first call's
variables with the second's.

Going  back to patterns, this gives us an added bonus. It not only
explains the behavior of hypotheticals, but also of subexpression
placeholders, which are created when the pattern returns:

    $self but lexicals(0=>$self, 1=> $self.{1}, 2=> $self.{2}, etc...)
    
That yields the side effect that you can say:
    
    sub match_digits($string //= $_) {
        return / (\d+) /;
    }
    if match_digits("The time is 12:03") {
        print $1;
    }

I think this is a very clean and simple way to get everything that
patterns were supposed to do plus a lot of added benefit for things
like:

    sub getpwuid(int $uid //= $_) {
        %pwd = external("getpwuid",$uid);
        return %pwd but lexicals(%pwd);
    }
    getpwuid($<);
    print "I am $user from $dir, and I have a secret ($passwd)\n";

You should be able to "protect" yourself from these side effects. There
are two ways to do that:

    {getpwuid($<)}

or

    getpwuid($<) but lexicals();

I would expect either one of those to work, though the second is a bit
of magic in terms of order of events.


-- 
Aaron Sherman <[EMAIL PROTECTED]>
http://www.ajs.com/~ajs

Reply via email to