Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

There was a learned discussion around this recently 715269 -- from which one concluded... well I wasn't sure...

The humble programmer needs a mental model for what goes on, and some way to describe it. So I wondered, what's wrong with the notion of a List in Scalar Context ?

The business of Context is peculiar to Perl, it's easy to miss first, second and possibly third time through. Bearing that in mind, this is what perldata says:

In a context not requiring a list value, the value of what appears to be a list literal is simply the value of the final element, as with the C comma operator. For example,
@foo = ('cc', '-E', $bar);
assigns the entire list value to array @foo, but
$foo = ('cc', '-E', $bar);
assigns the value of variable $bar to the scalar variable $foo. Note that the value of an actual array in scalar context is the length of the array; the following assigns the value 3 to $foo:
$foo = @foo; # $foo gets 3
So, blink and you've missed a number of things: ...first, the implication that a list (or at least a list value, or possibly a list literal) is not the same as an "actual array"; ...second, we can talk about an "array in scalar context" (so a "list in scalar context" seems natural); and...third, the author is in knots describing something that looks like a list, but isn't a list (and I want to meet the person who understood the fineness of that distinction the first time they read it).

But the notion of a list goes well beyond list literals, and we need a way to think about how lists are handled more generally.

You might think that lists are something to do with '()' as list constructor and ',' as list item separator. (Anonymous lists have the '[]' constructor...) Of course you would be wrong. The '()' are incidental, required because ',' is a sort of operator with lower precedence than '=', in particular. The '()' are not required at all in some contexts, notably following a list operator (eg print !).

Anyway, in the following, the stuff to the right of the '=' appear to be lists:

@r = () ; @r = undef ; # sets $r[0] = undef @r = 1234 ; @r = (12, 23, 34, 45) ; @r = 'a'..'z' ; @s = ('a'..'z')[4..15] ; @t = @r[7..16]; @q = 9..13 ; @u = @r[@q] ; @r{'a'..'z'} = (1..26) ; @w = @r{'k'..'p'} ; @p = 'k'..'p' ; @w = @r{@p} ;
so what happens if we change this to assignment to a scalar, so we have Scalar Context:
$r = () ; # Case 1 -- $r -> undef $r = 1234 ; # Case 2 -- $r -> 1234 $r = (12, 23, 34, 45) ; # Case 3 -- $r -> 45 $r = 'a'..'z' ; # Case 4 -- error $s = ('a'..'z')[4..15] ; # Case 5 -- $r -> 'p' $t = @r[7..16] ; # Case 6 -- $r -> 'q' $u = $r[@q] ; # Case 7 -- $r -> 'n' $w = @r{'k'..'p'} ; # Case 8 -- $w -> 16 $w = @r{@p} ; # Case 9 -- $w -> 16
Case 3 we are asked to understand in terms of the Scalar Context behaviour of the ',' operator, but can equally well be understood as a List in Scalar Context. Case 4 can only be understood in terms of the Scalar Context behaviour of '..' (in this case to whine about the arguments). However, all the other cases are consistent with the notion that there is a list on the rhs, and that in Scalar Context the result is the last item of the list -- and not a ',' operator in sight ! The List in a Scalar Context is holding up, so far...

Of course, we entirely understand that an Array or a Hash in Scalar Context is quite different:

$r = @r ; # Case 1 -- $r -> 26 $v = %r ; # Case 2 -- $r -> 19/32 $r = (@r) ; # Case 3 -- $r -> 26 $v = (%r) ; # Case 4 -- $r -> 19/32
The List in a Scalar Context notion might suggest that case 3 would set $r to the last entry in @r and case 4 would set $v to some value in %r, if you thought that '()' was a list constructor -- but it isn't, so it doesn't. So far so good, but what about:
$r = (@r, @r) ; $v = (%r, %r) ;
If we think about the rhs as a list, we may be disappointed -- in List Context, the @r or %r would be interpolated. That's not what happens here: the @r and %r are evaluated in Scalar Context, first; the result is then consistent with either List in a Scalar Context or Comma as a Scalar Operator views. (Remembering that ',' is just a list item separator, it's not a list constructor, and it has low precedence anyway.)

OK. The mental model so far, in expressions:

  • Context is important (!)
  • in List Context there are a number of things which make lists, including:
    • the empty list
    • singleton values (including undef)
    • literal lists -- two or more values separated by ',', grouped together by '()' if required
    • the '..' range operator
    • slicing other lists, arrays or hashes
  • in Scalar Context, the above constructs:
    • yield the last item of the list (undef for the empty list)
    • except for '..' which does something completely different in Scalar Context
    • noting, carefully that items in the list are evaluated in Scalar Context, if they are evaluated. (This is Perl Magic...)
  • Arrays are not the same as Lists
    • in List Context an array will evaluate to a list.
    • in Scalar Context an array will evaluate to the number of items in the list (more or less).

Now, subroutines: we have to understand that Context has a long arm -- the Context in which a subroutine is called, will, at a distance, apply to any expression yielding a return value. And different calls may provide different Contexts. This is slippery stuff, but at least the results are entirely consistent. If you take the examples above and replace each rhs by a call to a subroutine which returns that rhs, then the results are identical. But, it is worth noting that, for example, replacing:

return ($a, $b, $c, $d) ;
by:
my @return = () ; ... push @return, $a, $b ; ... push @return, $c, $d ; ... return @return ;
changes the Scalar Context result in a way that may slip your mind as you make an apparently straightforward change !

This is telling us something. A subroutine that is serious about being called in either Scalar or List Context, must ensure that it returns an explicit, well defined result in both cases -- which for Scalar may be the same as Array in a Scalar Context, or List in a Scalar Context, or anything else it cares to return. Further, it is foolish to call a subroutine in a Context which it does not explicitly support -- which implies that it is foolish to call a subroutine defined only to return a list, in a Scalar Context, and expect List in a Scalar Context semantics.

This is also true of Perl functions. There is no point assuming that a Perl function that returns a list in List Context will do anything useful at all in Scalar Context, except where it is defined to do so.

So, after all this (and thank you for reading this far!) am I clapping my hands ?

Well, yes I am. It seems to me that List in a Scalar Context is a perfectly good way of understanding the behaviour of lists in expressions, as discussed above.

However, the application is limited. In particular, it cannot be used to predict what a list returning operation will do if you decide to use it in Scalar Context. To that extent, the problem with the notion of List in a Scalar Context is that it is deceptively general, and dangerously so.

My conclusion: List in Scalar Context is a more general notion than Comma in Scalar Context, but you have to understand its limitations. And, it is much more important to understand that knowing that a Perl function or a subroutine returns a List in List Context, tells you nothing useful about its Scalar Context behavious.

I shall continue to clap, but in a quiet and restrained manner, as befits someone tip-toing through the minefield that is Perl Semantics !

BTW: I'm gagging to know how to describe why this:

$r = () = 1..27 ;
does what it does.

Finally, and for extra points (and points mean prizes), how does one describe the difference between a list and an array ?


In reply to If you believe in Lists in Scalar Context, Clap your Hands by gone2015

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2024-03-29 00:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found