in reply to Re: What's most efficient way to get list context? (honest)
in thread What's most efficient way to get list context?

What is the point of saying "I want a list context" if you don't actually want something from the list?...

The equivalent:

my $scalar = list function();

doesn't make sense because there is no universal "list in scalar context" behavior.

I find these remarks puzzling. As I understand it, the standard "list in scalar context" behavior is "size of the list". Furthermore, any function whose return value changes depending on the context (e.g. by using wantarray), gives rise to situations in which this hypothetical list operator would be useful. The canonical example of this is m//. If I want to find out how many times m/(pattern)/g matched, I have to resort to mysterious-looking trickery:

my $n = () = $string =~ m/(pattern)/g;
or else pointless, Javaoid verbositudinositiness:
my @useless = $string =~ m/(pattern)/g; my $n = @useless;
It seems to me more civilized to simply request m//'s list context behavior:
my $n = list $string =~ m/(pattern)/g;

the lowliest monk

Replies are listed 'Best First'.
Re^3: What's most efficient way to get list context? (count)
by tye (Sage) on Apr 15, 2005 at 07:02 UTC
    As I understand it, the standard "list in scalar context" behavior is "size of the list".

    No, no. The incorrect assumption you are supposed to make at this point is that a "list in scalar context" returns "the last item" (by default). But both assumptions are wrong. Each "operation that would return a list of scalars if called in a list context" makes its own, customized decision about what it will return in a scalar context and those two are just the most common choices (and "last item" is even more common than "number of items").

    There is no default choice. @x returns the size of the array. ( $x, $y, z() ) returns the value of z() (called from a scalar context). %h returns the bucket usage. Something I can't remember returns the first item. sort returns nothing useful (and does nothing useful to boot).

    Now a less "idiomatic" way to getting the size of an arbitrary list might be worth having. You didn't express it this way because of your wrong assumption about this being "the default" list-to-scalar conversion. So I'd rename the keyword "count" or such instead of "list", at which point it makes sense.

    - tye        

      Something I can't remember returns the first item
      caller, getpwuid, getpwent, more get* functions, but not all of them. get*nam return their third (or other) argument that they would have returned in list context.

      localtime returns a pretty printed version of its list context value. readdir, <>, each, .. and m//g iterate in scalar context. qw populates @_ in scalar context. And then there are reverse and x.

      OK, here is what I was trying to convey when I wrote the line you quoted:

      DB<1> @a = qw(foo bar baz) DB<2> @h{@a} = (1) x @a DB<3> p $s = () = @a 3 DB<4> p $s = () = (1, 2, 3, localtime()) 12 DB<5> p $s = () = %h 6 DB<6> p $s = () = getpwuid($<) 9 DB<7> p $s = () = sort @a 3
      As you can see, for all the cases you cited, when perl is coaxed into evaluating the RHS in a list context, and then the returned list is put in a scalar context, the result is the size of the list. I am not sure what is the correct wording to describe what I illustrate above, but it is clearly distinct from the fact that context-sensitive subexpressions will make idiosyncratic choices about how they respond to different contexts.

      In fact, as I illustrated with the m// example in my first reply to you, it is precisely the fact that different context-sensitive operations will make idiosyncratic choices for how they respond to a scalar context that makes it desirable to be able to explicitly instruct these operations to assume a list context, which is what the = () = kluge does.

      I readily admit that this is one of the areas of Perl that I have the hardest time with, as I've stated elswhere, so I really appreciate this discussion. I think our discrepancy here gets at the root of why this is such a persistent blind spot for me. As I'm beginning to understand it, there is a nasty tension between the whole DWIM thing on the one hand, and the idea that functions should do something "useful", even if idiosyncratic, depending on context. For DWIM to be possible, I think some consistency is necessary, otherwise "what I mean" will constantly be confounded by whatever usually-useful-but-idionsyncratic context-sensitive behavior functions may choose to adopt. But such consistency would prevent functions from behaving as usefully as possible. I think the only way to preserve both is to give the programmer the ability to explicitly specify context, just like we have the ability to explicitly specify precedence with ( )'s.

      Update: Fixed link.

      the lowliest monk

        when perl is coaxed into evaluating the RHS in a list context, and then the returned list is put in a scalar context,
        No, you can't "put {a list} in a scalar context".

        What you've done is demonstrate that the list-assignment operator ((...) = LIST) returns the number of elements assigned in a scalar context. This is both documented, and could just as easily invoke Nethack instead (although that would be less useful).

        That has nothing to do with "list in scalar context", because "list in scalar context" can't exist.

        It helps me to always think of the abstract syntax tree. Every node in the tree is some kind of operator/function. Every node is being evaluated in some sort of larger context (scalar/list/void, and to a lesser extent scalar can also be numeric or string). Every node can choose to return different things to each of those contexts.

        In your example, the "top node" is "list assignment operator". If you evaluate that in a list context, it returns a copy of the contents. If you evaluate that in a scalar context, you get the number of elements copied.

        At no time is there a "node" that has a strictly list value that is being evaluated in a larger context. In some sense, lists don't exist, except because someone applied list context to some node that can return a scalar or a list. Because there's no existing node that returns a list in a scalar context, it simply does not exist. You could probably write one in XS, and break things, but there's no existing one that does that. {grin}

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

Re^3: What's most efficient way to get list context? (honest)
by Roy Johnson (Monsignor) on Apr 15, 2005 at 11:57 UTC
    As I understand it, the standard "list in scalar context" behavior is "size of the list".
    You should note that your winner does not exhibit that behavior.
    grep 1, @list;
    would return a count (or the whole list, depending on context), but I suspect assigning to the empty list is more efficient. It's certainly a tad shorter to type.

    Update: Had grep 0, due to scrambled thinking that it would still return a count of all elements, yet not build a list. Gah. Thanks, Pustular.


    Caution: Contents may have been coded under pressure.

      You should note that your winner does not exhibit that behavior.

      Well there are two issues here (and as tye already noted, they are only meaningful in unusual situations such as benchmarking): one is what to wrap around an expression to induce perl to evaluate it in list context, and the other one is what is the value that this whole ball of code will return. The "winner" in my original node happens to do more than simply return the list that was produced by the wrapped expression. I can imagine any number of "wrappers" that would succeed in inducing a list context in the evaluation of the wrapped expreesion, and yet return entirely disparate things. And this is kind of my point: it makes no sense to have to wrap extraneous code around an expression just to "tell" perl to evaluate it in list context.

      the lowliest monk

        it makes no sense to have to wrap extraneous code around an expression just to "tell" perl to evaluate it in list context
        Assignment to an empty list is an easy and sensible way to apply list context to a function. It's no more extraneous than a list keyword; it's just more idiomatic.

        There's even a kind of symmetry: you can't assign a scalar to undef, so you have a scalar keyword; you can assign a list to (), so you don't need a list keyword.


        Caution: Contents may have been coded under pressure.