Marcus Gaius Publius Dominus on Sat, 28 Jun 2003 15:29:21 -0400


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

Re: scalar / list context weirdness


Jeff Abrahamson <jeff@purple.com>:
> But isn't
> 
>     $foo =~ s/.html$//;
> 
> scalar context?

Scalar or list context is not an intrinsic property of an expression.
It is a property not of the expression itself, but of the, er, the
context in which it appears.  

Imagine if someone were to ask you 

        "Isn't 'Do not touch that' in a satiric context?"

Then you would say "How should I know?  I would have to see the
context."

Any expression can be in list or scalar context; it depends on the
context, not on the expression.  In

        $s = EXPRESSION;

the expression is in scalar context; in

        @a = EXPRESSION;

it is in list context.

Here the statement under consideration is:
> >     @indices = map { $_ =~ s/.html$// } @indices;

The parse tree here is

        =
          @indices
          map
            =~
              $_
              s/.html$//
            @indices

The contexts for each operator are:

        =                               void
          @indices                      (no context)
          map                           list
            =~ s/.html$//               list
              $_                        scalar
            @indices                    list

The = is in void context because the value of the entire statement will be
thrown away.  If we had 

        if (@indices = map { $_ =~ s/.html$// } @indices) { ... }

then the = would be in scalar context.

@indices on the left is an lvalue--it is the target of an assignment.
Such expressions don't have a context, because context is all about
the value that an expression will produce when it is evaluated, and
expressions to the left of an assignment operator are not evaluated.

'map' is in list context, because it is on the right-hand side of an
assignment to an array expression.

=~ is a little funny, because the value it produces depends on whether
it is binding to a tr///, a s///, or a m// expression.    The simplest
way to think about it is that the =~ and the s/// are a single
expression.  They are in list context, because the first argument to
'map' is always in list context.  The essence of your question, then
is "what value does '=~ s///' produce in list context?"  I'll return
to this below.

$_ is in scalar context because it is bound to =~ s///, and an
expression bound to =~ s/// is always in scalar context.

Finally, @indices on the right is in list context, because the
additional arguments of 'map' are always in list context.

Now what about =~ s///?  

In scalar context, =~ s/// returns the number of successfully
performed substitutions, if there were any, and otherwise it produces
the empty string "", which happens to be false.

In list context, =~ s/// produces a list that always has exactly one
value.  That value is the number of successfuly performed
substitutions, if there were any, and an empty string if not.  That
is, it's a list with exactly the same value that it would have
produced in scalar context.

So the outcome of your 'map' expression is to concatenate these lists
together.  You get a list with one numeric element when a substitution
was done, and a list with one empty string element when no
substitution was done.

The context rules can be subtle.  Consider the common locution

        while (($k, $v) = each %hash) { ... }

Here the 'each' operator is in list context, but the '=' operator is
in scalar context.  People often find this sort of thing confusing.


-
**Majordomo list services provided by PANIX <URL:http://www.panix.com>**
**To Unsubscribe, send "unsubscribe phl" to majordomo@lists.pm.org**