http://qs321.pair.com?node_id=759480


in reply to Re: Why does foo() evaluate in array context in "${\foo()}"?
in thread Why does foo() evaluate in array context in "${\foo()}"?

This is puzzling...

perlref says "Anywhere you’d put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type."

We can see from ELISHEVA's example that the sub is called in list context. I assume, therefore, that it returns a list. But a list isn't "a reference" even if every element of the list is. Is there an undocumented case of the block returning a list? Or am I wrong to think that the sub returns a list? If it doesn't return a list, what does it return and why?

Had the sub been called in scalar context then, because there is no such thing as a list in scalar context, what does \(LIST) become?

sub foo { \('fred', 'bill') };; print "${ scalar(foo()) }"; __END__ Returns: bill

So I know what happens in the end, but I'm having trouble reconciling my model of what perl does and what the various expressions mean.

update: Considering JavaFan's post I see my mistake: the sub is called in scalar context, not list context. The call is not the same as in ELISHEVA's original post. And perlref says \($a, $b, $c) is the same as (\$a, \$b, $\c). I conclude that in scalar context the latter is simply not a list.

update2: Changed "array context" to "list context" throughout, because that's what it is called.

update3: Clarified what perlref says and what I conclude/assume.

Replies are listed 'Best First'.
Re^3: Why does foo() evaluate in array context in "${\foo()}"?
by BrowserUk (Patriarch) on Apr 23, 2009 at 09:54 UTC
    because there is no such thing as a list in scalar context,

    My take on it is that this is the exception that disproves that rule. Whilst others will disagree and probably decline to comment.

    If you put that thing--two or more things separated by commas--that we're told is not a list, in a scalar context, at compile time, then the compiler knows the list is useless and can discard all but the last element. This is shown nicely by Deparse:

    C:\test>perl -MO=Deparse -e"print scalar( 'fred', 'john', 'bill' )" print scalar('???', '???', 'bill'); -e syntax OK

    And backed up by warnings:

    C:\test>perl -we"print scalar( 'fred', 'john', 'bill' )" Useless use of a constant in void context at -e line 1. Useless use of a constant in void context at -e line 1. bill

    But construct that same thing in a way that the context is not directly discernable at compile-time, and it has no choice but to construct a list er, leave the thing intact.

    Again nicely shown by Deparse:

    C:\test>perl -MO=Deparse -e"print scalar( sub{'fred', 'john', 'bill'}- +>() )" print scalar sub { 'fred', 'john', 'bill'; } ->(); -e syntax OK

    And no warnings either:

    C:\test>perl -we"print scalar( sub{'fred', 'john', 'bill'}->() )" bill

    Just a list thing in a scalar context being reduce/resolved/resulted to the last element of that list thing.

    what does \(LIST) become?

    The only way left to describe it is that the thing (that would be a list in a list context), becomes the last element of that thing when it finds itself in a scalar context. :)


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Thank you!! for the examples and lucid explanation.

      I certainly don't want to restart the If you believe in Lists in Scalar Context, Clap your Hands discussion - which convinced me that "list in scalar context" is disturbing and possibly misleading enough to many people to be worth avoiding. But I have yet found no description better than what you closed with and that, while it might be quite correct, seems less than ideal as a high level abstraction by which to grok Perl. Being verbally oriented, this continues to trouble me.

Re^3: Why does foo() evaluate in array context in "${\foo()}"?
by gone2015 (Deacon) on Apr 23, 2009 at 10:02 UTC

    As JavaFan says, contrary to most expectations \ actually provides LIST context ! So:

    #!/usr/bin/perl -w use strict ; use warnings ; sub foo { my ($tag) = @_ ; print "$tag: ", wantarray ? "LIST" : "SCALAR", "\n" ; return wantarray ? ('a', 'b') : \78 ; } ; my $a = \foo('SCALAR \foo()') ; my @a = \foo('LIST \foo()') ; my $b = ${foo('SCALAR ${foo()}')} ; my @b = (${foo('LIST ${foo()}')}) ;
    gives:
    SCALAR \foo(): LIST
    LIST   \foo(): LIST
    SCALAR ${foo()}: SCALAR
    LIST   ${foo()}: SCALAR
    
    which also shows that ${...} does provide SCALAR context as expected.

    This behaviour is not mentioned in perlop and I cannot see it in perlref either :-(

    It is documented that \($a, @b, %c) is the same as (\$a, \@b, \%c). Which requires the , to be operating in LIST context -- so perhaps we should not be surprised. (It's also worth remembering that LISTs are interpolated when they are evaluated, not when they are constructed...)