in reply to Array in scalar context.

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.


Dave


"If I had my life to do over again, I'd be a plumber." -- Albert Einstein

Replies are listed 'Best First'.
string context and list operators (was Re: Array in scalar context.)
by jonadab (Parson) on Oct 04, 2003 at 16:50 UTC
    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?
        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" ?

        Yes. But because you added a constant (0), you're now evaluating the result of an addition, which is a number. You're no longer evaluating the variable $!, and so the string magic of $! doesn't come into play. Instead, the number (e.g., 2) gets stringified.

        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 ?

        Well, interpolation is different than ordinary string context (or flattened list of strings context, for that matter). Many things that would be evaluated in one fashion or another outside a string (even in string context) are evaluated differently inside a string. For example, consider the hash %foo. In list context, it will return a flat list containing each key and its corresponding value. In string context, it will return something different. (Try it: %foo=(bar=>3); print %foo."\n";.) If you try to interpolate it into a string, in Perl5 you get "%foo". (Way back in the day, it was decided that Perl should have the same sprintf syntax as C, and so when array interpolation was added, hash interpolation along the same lines couldn't be. This will be remedied in Perl6, which is revamping a lot of things that needed to be revamped.) Also, in Perl5, method calls don't interpolate. (In Perl6, they will.) So a method call that does one thing in string context will do something else when you try to interpolate it. If you like, you can think of interpolation as its own type of context.

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

        For the same reason that print 'perl', 'monks'; does the same thing. Remember, print flattens its list of arguments and deals with them individually, so if you pass it an array (or a list), it doesn't see the array (or the list) as a whole, but the individual elements. join does the same thing. push and pop do this with everything except their first argument (which must be an array). Many of the other list operators function this way as well, and if you write your own function that loops over @_, it will behave in this same way: you can pass it arrays, but they are flattened, and the function sees only the elements. When a function takes an array AS SUCH, like push and pop do with their first argument, that's a noteworthy and special feature of that function. If you think print should print something between the values it prints, assign a value to $"

        4. What are all the contexts (like numeric context, string context) that exist which are variations of scalar context or list context?

        I might miss something, but the scalar contexts I can think of are string context, numeric context, general scalar context (created e.g. by assignment to a scalar variable, or by using the scalar keyword), boolean context (present in a condition), and there are also special contexts associated with specific Perl builtins, such as ref and defined and exists, which evaluate their arguments in special ways. Oh, and some people would add void context (where the return value is just thrown away), though I'm not sure that's scalar per se.

        Oh, you asked about list contexts too. Hmmm... Perl5's concept of list context is fairly basic, though of course the _elements_ of the list may be evaluated in a certain scalar context. (For example, print evaluates the elements of its argument list in string context, so you can think of the overall context supplied by print as flattened-list-of-strings if you like.) In Perl6, a lot more richness is being added to this, so that a function can supply an argument with for example a pairlist context. As far as I know Perl5 doesn't really have this. As an example of the difference, in Perl5 if your function is called as an argument to print, it can use the wantarray function to find out that it's being called in list context, but that's all: it can not determine that a list of strings is wanted, rather than a list of numbers for example. In Perl6 it will be possible for a function to use the want builtin to determine such things, and so it would be possible for a function to return one thing in list-of-strings context and return something different in list-of-numbers context and yet something different in list-of-pairs context -- perhaps pairs containing both the number and the string. Though, in practice, a Perl6 function would probably be more likely to return a list of objects that know how to provide the desired values in various contexts. That way if what the function returns value is assigned to an array for later use, there's no problem about knowing which kind of values are wanted.


        $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/