Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Array in scalar context.

by the_0ne (Pilgrim)
on Oct 04, 2003 at 02:41 UTC ( #296453=perlquestion: print w/replies, xml ) Need Help??
the_0ne has asked for the wisdom of the Perl Monks concerning the following question:

I was reading through the new Perl Cookbook, particularly the Arrays chapter. I noticed the author states you must use the scalar function to find the count of elements in an array. Is this something that has changed? I've used code like this all over the place...
@foo = ( 'foo', 'bar' ); print "There are " . @foo . " elements in foo.\n";
...and it works. Is there a pitfall I'm missing? This threw me a little since I don't use the scalar function unless I have to. Is there a problem here or has what the author stated changed in the current version of perl. I'm using Mandrake Linux with perl 5.8.0. It's not a huge deal, but I want to make sure I change some of the places I've used it like the way above before I fall into the pitfall.

Thanks Monks.

Replies are listed 'Best First'.
Re: Array in scalar context.
by Zaxo (Archbishop) on Oct 04, 2003 at 02:52 UTC

    That should read that you must use the scalar function to find the count in list context... The scalar function simply puts its argument in scalar context, independent of the external context.

    Your usage is correct, though you would get a surprise if you changed the concatenation dots to commas for efficiency. That would put @foo in list context and you'd get the array contents spilled to the selected handle.

    After Compline,

Re: Array in scalar context.
by davido (Archbishop) on Oct 04, 2003 at 03:03 UTC
    Nothing's changed. The assertion the book is making is that you must ensure that the array is being seen in scalar context, not list context. Think of an array as a container for a list. Inside the container is the list. On the lid is a label that tells how many elements are contained inside. In scalar context, you're looking at the label on the lid. In list context, you're looking at the contents of the container.

    To explain the "Do what I mean" behavior you show in your example......
    It makes no sense for a list to be operated on by the concatenation operator. The concatenation operator takes a scalar on both sides. Thus, if you were able to call "wantarray" on the concatenation operator you would find that it doesn't "want a list." That fact forces the @foo array to be evaluated in scalar context, and the results of that evaluation to be concatenated with whatever is on the other side of the "." operator. As we all know, the good book says, "There is no such thing as a list in scalar context." When you put an @array somewhere that a scalar is expected, you get the behavior documented for @array in scalar context; you see how many elements it contains.

    If, on the other hand, you say, print @foo you will see that print accepts a list (and prints a list). If you could call wantarray (an apparent misnomer with origins in the dark ages when lists were called arrays too) on "print" it would return true. And so, @foo is evaluated in list context when evaluated as an arguement of 'print'.

    The most peculiar thing I can think of in all this is the fact that concatenation operator doesn't accept a list while variable interpolation into a string does. I know that "concatenating" lists is what join is for. But to a relative greenie like me, it seems inconsistant. (For example, "This @array interpolates as a list.")

    Perhaps our lives are simpler and better because arrays inside of literal strings are seen as arrays in list context, but nevertheless, why that "works" when concatenation doesn't is something that the real experts will have to reveal.


    "If I had my life to do over again, I'd be a plumber." -- Albert Einstein
      The concatenation operator takes a scalar on both sides.

      This is correct as far as it goes, but the truth is more specific...

      The most peculiar thing I can think of in all this is the fact that concatenation operator doesn't accept a list while variable interpolation into a string does. I know that "concatenating" lists is what join is for. But to a relative greenie like me, it seems inconsistant.

      You're missing a small bit of the contextual richness that makes Perl so cool. The binary concatenation operator evaluates its left and right arguments in string context, which happens to be a particular variety of scalar context. You can see this difference for example if you concatenate $!

      $! = rand(7); print("In numeric context it's ". ($!+0)." but in string context it's " . $! . $/);

      The join function is a list operator, like print. It evaluates each argument in string context, but it takes those arguments as a flattened list. You can write your own function that does this:

      sub listop { my @result; for (@_) { push @result, "".$_; } @result; }
      #update: or, more concisely, sub listop{map{"".$_}@_}

      You can pass this thing an array or list (or several arrays or lists), and it will return a list containing all the elements, with each one stringified. This is basically what join and print do, except that rather than returning that list they do something interesting with it.

      $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
        I am a perl newbie. I wanted to confirm few things based on your answer. Here are my questions

        1. The operation ($!+0) causes $! to be evaluated in numeric context because of the binary + operator. The parenthesis around $!+0 are necessary here because of the preceeding concatenation operator which is left associative and has the same precedence as that of binary + operator. Now, once $!+0 is evaluated in numeric context, to say number 2, does it again get evaluated in string context by the preceeding concatenation operator to string of one character i.e. "2" ?

        2. Within a string, say "Hello World!", the default context is string context. So if I have,

        @array = (perl, monks); print "Hello @array World!";
        @array is evaluated in string context inside "Hello @array World!" so as to yield a single string "perl monks" which is then interpolated into "Hello World!" so as to give "Hello perl monks World!".
        Is this observation true? and is this what you are refering to as the "flattaned list" the join operator accepts ?

        3. Why does
        print @array;
        prints: perlmonks
        instead of: perl monks ?

        4. What are all the contexts (like numeric context, string context) that exist which are variations of scalar context or list context?
Re: Array in scalar context.
by Roger (Parson) on Oct 04, 2003 at 03:07 UTC
    No, you are not missing anything. In your print statement, perl automatically converts @foo to scalar(@foo) because of the join (.) operator in use.

      I understand now, thank you all.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://296453]
Approved by broquaint
Front-paged by davido
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2017-01-22 17:15 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (189 votes). Check out past polls.