[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 10-fyi-autom4te-trace-patterns.patch

From: Russ Allbery
Subject: Re: 10-fyi-autom4te-trace-patterns.patch
Date: 10 Aug 2001 01:10:36 -0700
User-agent: Gnus/5.0807 (Gnus v5.8.7) XEmacs/21.1 (Channel Islands)

Akim Demaille <address@hidden> writes:

> Err, maybe :)  Here is what I'm trying to do:


> (but again, it is my understanding this is prohibited for `my': if I use
> `local $bar' both work.  I want to know if there is a means to do that
> with `my' vars).

Oh, you *do* want to change the my variable!  Okay.  No, I don't think
there's any good way of doing that... well, for one thing, once you call
another sub there's no way for that sub to modify any my variables in the
calling sub.  Think of my variables like automatic variables in C; they're
local to a particular scope or anything enclosed in it.

The only way that I can think of to do this is a really ugly hack; read
the entirety of the file into memory as a string and then call eval on
that string in the scope where you want to modify variables.  That will
execute the code as if it were inlined into that spot in the sub that
calls eval, which will let it modify my variables and pretty much anything

> Russ> is that you're using it inside the code block of a map or grep,
> Russ> so it *is* in a scalar context.

> OK.  What can I do to tell it its an array context?

Actually, I think I was completely wrong there; map *does* provide an
array context to the code block.  That's not the problem; the problem is
that chop just doesn't return its argument.  It modifies its argument and
returns the character that was removed.

> Russ> What you want in this case so far as I can tell is to grap all
> Russ> of the patterns in @patterns beginning with "forbid:" (or
> Russ> "allow:") and store them in a variable, separated by |, with the
> Russ> prefix removed.  Try:

> Russ> my $forbidden = join ('|', map { /^forbid:(.*)/ } @patterns) || "^\$";

> Hm, I had not realized either I could use $1...  Thanks!

Note that this isn't really using $1, in the sense of using the Perl $1
variable.  It's actually using the return value of the m// match
expression, which in list context is a list containing all of the
parentheses matches found in the regex (or if there are no parentheses in
the regex, the text that the regex matches).  It so happens that in this
case $1 and the return value of m// are *mostly* the same (but with one
exception; see below).

> I have one last question.  The documentation for map says:

>        map BLOCK LIST
>        map EXPR,LIST
>                [...]  Evalu­
>                ates BLOCK or EXPR in list context, so each ele­
>                ment of LIST may produce zero, one, or more ele­
>                ments in the returned value.

> and I just don't know how to return 0 elements.  I tried this, without
> success:

Return an empty list.

This is an obscure corner of Perl, but basically Perl flattens lists.  So,
for example, if you assign something in list context like this:

    @list = (1, 2, (), 3, 4, (), 5);

with empty lists in it, the empty lists disappear:

windlord:~> perl -e '@list = (1, 2, (), 3, 4, (), 5); print "@list: $#list\n"'
1 2 3 4 5: 4

Note that there's five elements in the resulting list, and it's just as if
the empty lists didn't exist.  This is just a special case of general list
flattening; consider:

windlord:~> perl -e '@list = (1, 2, (3, 4), 5); print "@list: $#list\n"'
1 2 3 4 5: 4

So to return nothing from a map block, return ().  That's the reason why
this doesn't work:

> my @list = ('0: even', '1: odd', '2: even', '3: odd');

> my @evens = map { $1 if m/(\d): even/ } @list;
> my @odds  = map { $1 if m/(\d): odd/  } @list;

Here, you're no longer returning the value of m//; you're returning the
value of the scalar variable $1.  $1 is going to either contain a match or
will be undef, which join will turn into the empty string.  That's not
what you want, though; you don't want a list that contains a few undefs,
but instead you want the items that don't match to just disappear.  This
is where the return value of m// comes in handy; because it returns a list
of the matching parens, when the pattern doesn't match it returns an empty
list which then does exactly what you want.

Russ Allbery (address@hidden)             <>

reply via email to

[Prev in Thread] Current Thread [Next in Thread]