in reply to Re: Scalars, Lists, and Arrays
in thread Scalars, Lists, and Arrays


Thank you for the explanation. Let me see if I have this right:

  1. There are two contexts in which an expression can be evaluated: scalar and list.
  2. There are three major types of variables in perl: scalars, arrays, and hashes. 'Scalar' variable type and 'scalar' context are not the same thing, although scalar variables usually impose scalar context.
  3. Expressions are either constants, the values of variables (either lvalue or rvalue), or the results of functions which may take other expressions as arguments.
So my principle error lies in trying to compare lists and arrays, which are different types of things. The confusion is partly caused by 'scalar' being both a context and a expression variable, and thus capable of being compared with either. Hence, comparisons are not transitive!

Is this right?

Be bloody, bold, and resolute; laugh to scorn
The power of man...

Replies are listed 'Best First'.
Re: Re: Re: Scalars, Lists, and Arrays
by merlyn (Sage) on Apr 13, 2001 at 17:37 UTC
    I've also found it important to thump the desk when I'm teaching about this topic, over two very specific things:
    1. A list never gets produced in a scalar context.
    2. What a construct does produce in a scalar context must be learned, not derived by any general rule.
    So, if you learn about what @foo does in a scalar context, that tells you nothing about what @foo[3..5] does in a scalar context, or even what ($x,$y,$z) does in a scalar context. You must learn them each individually.

    As it turns out, there is a bit of consistency in it (it's not just random madness), but that's available only after the fact. {grin}

    -- Randal L. Schwartz, Perl hacker

      I'll agree with your "A list never gets produced in a scalar context", but only for certain values of "never", "list", and/or "produced". :) That is an important concept that needs to be stressed (though I'd put less stress on the "never" part myself).

      But, for the curious, see the last half of (tye)Re: Hash slices ? for a specific example of what I consider to be a list of SVs being (temporarily) produced despite a scalar context. I'm not trying to contradict the above rule. I am trying to prevent it from being "over interpreted", but more than that, I think the example will help some people understand the concept better.

              - tye (but my friends call me "Tye")
Re: Re: Re: Scalars, Lists, and Arrays
by sierrathedog04 (Hermit) on Apr 13, 2001 at 20:07 UTC
    There are other contexts as well. Camel III lists three of them. They are:
    • Boolean context, such as when we test for the existence of values in an array.
      while (@files) { my $file = shift @files; unlink $file or warn "Can't delete $file: $!\n; }
    • Void context. It is unclear from Camel III what this context does. The example Camel III gives is a statement consisting of the quoted string "Camel Lot"; Apparently the -w option on the perl interpreter does not like this context, and returns a warning on it. Maybe it's best to avoid this one altogether.

    • Interpolative context, which occurs inside quoted strings when one includes a variable name. The substitution operator s/// and some other expressions also occur in interpolative context.

      Boolean context is ubiquitous, so let's give this little brother of list and scalar its due!

      Void context is where you have an expression (not to abuse Dominus' terminology too much) that doesn't go anywhere. For example, if you had:
      open(FILE, $filename) or die "Can't open $filename: $!"; "nothing to see here"; close FILE;
      Ignoring the fact that the program does nothing, the second line is a scalar expression (help me out here, if I abuse verbiage) in void context.

      When you abuse map to iterate over a list and don't assign the results to anything, you're using map in void context.

      It's generally not useful, but if you have an expression that can spend a lot of time creating a result value of some sort, it can be inefficient to use void context.

      Says sierrathedog04:
      Boolean context is ubiquitous, so let's give this little brother of list and scalar its due!
      "Boolean context" is 100% identical with scalar context. It is a fiction.

      Interpolative context
      That is not a context, because expressions are not evaluated in double-quoted strings. What value does localtime() produce in "The time is: localtime()\n"?

      Void context
      This one is a little different. For built-in Perl operators, it's identical to scalar context. The only time it might be different is for a user-defined function that explicitly tests whether wantarray yields an undefined value, and which does something different if so. Regardless, there's no question about what the return value is.

      The interesting one I think you left out is that the argument of defined is a different kind of context. defined(&foo) doesn't even call &foo.

        *sigh* let's not go overboard on what can and can't be called a "context", either.

        So-called "Boolean context" is a useful concept, especially if you are dealing with overloaded objects. I agree that it is important to realize that it isn't a "context" in the same way that "scalar context", "list context", and "void context" are and that using something in a "Boolean context" is hard to distinguish from using it in a scalar context (though it can be done by using overloading). I'd love to see an enhancement that elevates "Boolean context" to being a "first class context" (well, at least "second class" if you don't count "void" as "first class") by, for example, adding a OPf_WANT_BOOL flag.

        "Interpolative context" can also be a valuable concept for explaining why these are different:

        print "@a"; print "".@a; print @a;
        even though it is very much different than the "big three" contexts. This one reminds me of the "numeric", "string", and "integer" pseudo contexts.

        For built-in Perl operators, [void context] is identical to scalar context

        Doing a quick search, I found that keys knows the difference between scalar and void context so that it can avoid some work in the latter case. I suspect there are more than a few other cases. I'm not trying to contradict you, I just don't want others to overinterpret what you are saying.

        I guess that by "do something different" (in the case of a user-defined function detecting void context) you are referring to "side effects" and that you are asserting that no built-in functions/operators of Perl have different side effects between scalar and void context. I would certainly be somewhat surprised to find a case that violates such an assertion but I wouldn't feel comfortable making that assertion myself.

        I'd take issue with your using "context" to describe the special way defined works but that would just seem ornery of me. A similar "context" that I'm finding increasingly interesting is the "pseudo code block context" that is given to the first argument of map or grep:

        map func($_), @list; grep func($_), @list;

                - tye (but my friends call me "Tye")
      Void context ... Maybe its best to avoid this one altogether

      Void context is where you're performing an operation and doing nothing with the result. That is,
      #!/usr/bin/perl -cw "String";
      tells me:
      Useless use of a constant in void context at - line 2.
      In fact, I care about this because it generally indicates a problem with my program. What use is a constant where I don't store what that constant is?

      Void context can be useful. Consider:
      grep { s/\s+$// } @lines;
      which will remove all trailing whitespace from all the lines I have in @lines. grep normally returns the lines that matched the pattern. But because I'm in void context, the values just get thrown away and all I'm left with is @lines which contains every line missing its trailing whitespace. (By the way, the better way to do that is:
      foreach (@lines) { s/\s+$// }

      Consider also that some objects require methods to be run in void context. While you're not just throwing away their values, these things have side effects that perform useful work. For example, in CGI, you can do:
      which, while run in void context, imports all parameters into the 'R' namespace.

      So, in summary, -w isn't complaining because you're running things in void context. It's complaining because you're running in void context without doing anything that could be construed as useful.

      Update: D'oh, chromatic beat me to it.