in reply to Re: string context and list operators (was Re: Array in scalar context.)
in thread Array in scalar context.

Thanks again for your reply. Since I am new to PERL it takes a long time to go through the responses and understand them. Once again here are my questions. Thanks for your help.

1. On wantarray/want and context

(a) what I understand by the definition of wantarray
The wantarray function can be used inside of a subroutine definition to determine the context in which that subroutine is called. By default, such a context is available to the return statement of the subroutine. But if the context is to be known in other parts of the definition of the subroutine then wantarray needs to be used. Is this observation true ? Is the real usage of wantarray just limited to using inside of a subroutine ?

(b) In the program,

sub test_wantarray{ wantarray ? Y : N; } print "Hello" . &test_wa . "World\n"; print "Hello", &test_wa, "World\n";
output:
HelloNWorld HelloYWorld
In the first print function, the concatenation operator supplies the context to subroutine test_wantarray. Hence wantarray from inside of test_wantarray finds this context to be a scalar context and returns N. In the second print function, since the comma operator (,) doesn't supply a context of it's own, the subroutine test_wantarray is operating under the context supplied by print function. Hence wantarray from inside of test_wantarray finds this context to be list context and hence returns Y. Is this what davido meant by "IF YOU COULD call wantarray on print function it would return true." and am I successful in calling wantarray on print function (i.e. in the case of second print function)?

(c) Since the above subroutine test_wantarray is just one line, if the subroutine call is replaced in the above print function to be,

print "Hello", (wantarray ? Y : N), "World\n";
it prints: HelloNWorld. Is it that wantarray can only be used inside a subroutine? Can you explain about what you mentioned earlier? i.e. "you are not calling wantarray in the context that print supplies, in the context that ternary operator supplies" ?

If the ternary operator context is scalar how can it return a list if the expression for this ternary operator evaluates to true and an array is to be returned? i.e. in cases such as,
sub test_wantarray{ wantarray ? @array: \@array; }
Why this scalar context of ternary operator doesn't come into play inside of the subroutine test_wantarray ?

(d) Refering to the print function in the above sub section (b)

print "Hello", &test_wa, "World\n";
returns true confirming that the print function is providing a list context to it's arguements. If such is the case,
why provide a list context to it's arguments only to see to it that print cannot operate on them (or rather it has to flattens them)? Why not just provide a "flattened list context" where the argument list/array isn't seen but only the individual elements within the list/array ? i.e. in your earlier reply you mentioned "print and join both take a flattened list". What am I missing here ?

(e) I looked at want module documentation (http://dev.perl.org/perl6/rfc/21.html) but wasn't able to understand. Is the real use of this,

(i). want should be able to distinguish between various type of scalar contexts or various type of list contexts when used inside of a subroutine . Can you please provide an example ?
(ii). how does it get down to small constructs (as opposed to wantarray) ? Can you please provide an example ?

2. If the return value of an expression is, undef or "" or number 0 would they all evaluate to false value in boolean context?

3. Can we confirm from the below program that, the internal value of undef is the ASCII null value (ie. ASCII code: 0)

if (undef eq "") { print "undef evaluates to empty string in string context\n"; } if (undef == 0) { print "undef evaluates to zero in numeric context\n"; }

4. In the below code

$count = () = $s =~ /abc/g;
Did you get any chance to find out what exaclty causes $count to return the number of times abc appears in $s instead of  abcwhen you mentioned that "....I'm not sure what magic causes $count to come out as a number instead of "abc". It may be that what I'm missing has to do with the difference between m/foo/g and s/foo/bar/g. The latter I use much more frequently than the former, but they work differently. I'll try to remember to look into that and reply again if I figure out exactly what's going on there."

5. Just wanted to know, where did you come accross the information that your earlier mentioned i.e. "....way back in the day it was decided that the array interpolation inside double quoted string should have the same syntax as that of sprintf of C. So when array interpolation was added, hash interpolation along the same lines couldn't be. This will be remedied in PERL 6....". I just needed this detail just to understand why hash interpolation couldn't be added.

Replies are listed 'Best First'.
Re: string context and list operators (was Re: Array in scalar context.)
by jonadab (Parson) on Oct 19, 2003 at 04:30 UTC
    The wantarray function can be used inside of a subroutine definition to determine the context in which that subroutine is called.

    Yes, exactly.

    By default, such a context is available to the return statement of the subroutine.

    Well, you could view it that way, insofar as whatever expression you are returning (either by explicit return or implicitely by virtue of its being the last thing evaluated in the function) will be evaluated in the supplied context, yes. But if you want to return something entirely different in different contexts, then you use wantarray (or, in Perl6, want).

    Is the real usage of wantarray just limited to using inside of a subroutine?

    Yes, wantarray tells you the context in which the current routine was called. Now, that routine can be a named sub, or it can be an anonymous sub ("closure"), or a method. In Perl6 it can also be a multimethod or (I think) a rule. All of these you can think of as one type or another of subroutine, so the statement "wantarray tells you the context in which the current subroutine was called" still holds true irrespective of which exact type of subroutine that is.

    sub test_wantarray{ wantarray ? Y : N; } print "Hello" . &test_wa . "World\n"; print "Hello", &test_wa, "World\n"; output: HelloNWorld HelloYWorld
    In the first print function, the concatenation operator supplies the context to subroutine test_wantarray. Hence wantarray from inside of test_wantarray finds this context to be a scalar context and returns N.

    Yes, exactly.

    In the second print function, since the comma operator (,) doesn't supply a context of it's own, the subroutine test_wantarray is operating under the context supplied by print function. Hence wantarray from inside of test_wantarray finds this context to be list context and hence returns Y.

    Basically, yes. Some people will tell you that there are two different comma operators, one that operates in scalar context and one that operates in list context, but even if you view it that way, it is still true that the list context is present because that is what print supplies; if you were to replace print with a function that supplies scalar context, test_wa would not be called in list context. (Actually, it would be called in void context, because only the last value of the "list" would be wanted. People who believe in two different comma operators would say that the scalar comma always supplies void context to its left operand. I prefer to think that Perl knows only the last value of the list is wanted and evaluates the others in void context. Either way, test_wa is called in void context.)

    sub print_context { if (not defined wantarray) { print "[void context]"; } elsif (wantarray) { print "[list context]"; } else { print "[scalar context]"; } return undef; } "Hello", print_context, "World\n"; # void context print "\n"; "Hello " . print_context . "World\n"; # scalar context print "\n"; print "Hello " . print_context . "World\n"; # scalar context print "\n"; print "Hello", print_context, "World\n"; # list context print "\n"; join print_context, # scalar context print_context, print_context; # both list context print "\n";
    Is this what davido meant by "IF YOU COULD call wantarray on print function it would return true."

    Yes.

    and am I successful in calling wantarray on print function (i.e. in the case of second print function)?

    Indirectly, yes.

    Since the above subroutine test_wantarray is just one line, if the subroutine call is replaced in the above print function to be, print "Hello", (wantarray ? Y : N), "World\n"; it prints: HelloNWorld. Is it that wantarray can only be used inside a subroutine?

    Yes. If you put that code inside a subroutine, it will print something different depending on the context in which you call that subroutine.

    Can you explain about what you mentioned earlier? i.e. "you are not calling wantarray in the context that print supplies, in the context that ternary operator supplies"?

    I was talking about the same thing you were just now talking about: wantarray takes its notion of context from the current routine, not necessarily the immediate local grammatical construct. This is actually useful; if wantarray took its notion of context from the immediate context, you would not be able to test it easily, because your test condition would always supply a boolean context. For example if we had a mythical immediate_context operator that returned the immediate context in which it was called, and we tried to use it, ... print (immediate_context?"list":"scalar or void"); we would always get "scalar or void", even though print supplies a list context, because the trinary operator (foo?bar:baz) supplies boolean context (which is a type of scalar context) to its leftmost operand. So, ...

    print_context() ? print_context() : print_context(); print "\n";

    This prints "[scalar context][void context]", because the boolean context in which the first print_context is called is scalar, and so the second one (between the ? and the :) is not called, and the third is called in void context.

    If the ternary operator context is scalar how can it return a list if the expression for this ternary operator evaluates to true and an array is to be returned? i.e. in cases such as,
    sub test_wantarray{ wantarray ? @array: \@array; }

    The trinary operator supplies boolean context to its leftmost operand. The middle or right operand (whichever is evaluated) is evaluated in the context inherited from the context in which the whole expression is found. In this case, the expression is the last thing evaluated in the subroutine, so it is an implicit return, and so it inherits the context in which the routine was called. Try these:

    print_context() ? print_context() : print_context(); print "\n"; print print_context() ? print_context() : print_context(); print "\n"; print join(print_context() ? print_context() : print_context()), print +_context(), "\n";
    Refering to the print function in the above sub section (b) print "Hello", &test_wa, "World\n"; returns true confirming that the print function is providing a list context to it's arguements. If such is the case, why provide a list context to it's arguments only to see to it that print cannot operate on them (or rather it has to flattens them)? Why not just provide a "flattened list context" where the argument list/array isn't seen but only the individual elements within the list/array ? i.e. in your earlier reply you mentioned "print and join both take a flattened list". What am I missing here ?

    Flattening. Just as an array is in this context not a single argument, but is "flattened" into its elements, so also a subroutine call is "flattened" into as many elements as it can provide, which all become part of the list that the function (in this case print) sees. This happens anytime a function calls for a flat list, which is the default for all functions that do not explicitely set a different prototype.

    I looked at want module documentation (http://dev.perl.org/perl6/rfc/21.html) but wasn't able to understand. Is the real use of this,

    This "documentation" you were looking at was someone's suggestion (Damian Conway's suggestion, as it happens) for how things ought to be in Perl6. If you want to see the answer to this suggestion, and an explanation of how this will actually be in Perl6, see Apocalypse 6. For a simpler explanation (by, as it happens, the same Damian Conway who wrote the suggestion you looked at), see Exegesis 6.

    If what you wanted was the documentation for the Want module for Perl5, you want to look for it on search.cpan.org (which is, generally, the best place to find documentation for many modules).

    If the return value of an expression is, undef or "" or number 0 would they all evaluate to false value in boolean context?

    Yes. undef, "", and 0 are all false in boolean context. Also, "0" if I am not mistaken is false in boolean context. However, "0.0" or "0 but true" (as strings) are true. Also, a list containing a single value which is undef is true. When undef is the entire list, it is considered to be a list containing no elements, and _that_ would be false, but if undef is an element in the list, then the list contains elements (at least one element) and therefore is true. Usually, this is all exactly what you would intuitively think, but occasionally it can be handy to know exactly what is what.

    Can we confirm from the below program that, the internal value of undef is the ASCII null value (ie. ASCII code: 0)

    Not necessarily. For one thing, the ASCII null in Perl does not have the same semantics in a string as it does in C. It is just another character, in fact, with no special meaning at all to Perl. I believe undef in Perl is like nil in lisp: it is a value in its own right, distinct from other values such as zero. (Also, it may not be entirely a conincidence that both undef in Perl and nil in lisp are synonymous with an empty list containing no elements. Perl probably borrowed this idea from lisp or one of its derivatives.) The reason it evaluates to the empty string in string context and zero in numeric context is because Larry Wall thinks (probably rightly) that this is the least unexpected thing for it to do in those circumstances, not because of the way it is stored internally. Perl, generally, tries to do what is right, or what is wanted, or what makes sense, rather than basing its behavior on lowlevel implementation details. There are places where the implementation details leak through, but I do not think this is one of them.

    $count = () = $s =~ /abc/g;

    I still intend to get to that...

    Just wanted to know, where did you come accross the information that your earlier mentioned i.e. "....way back in the day it was decided that the array interpolation inside double quoted string should have the same syntax as that of sprintf of C. So when array interpolation was added, hash interpolation along the same lines couldn't be. This will be remedied in PERL 6....". I just needed this detail just to understand why hash interpolation couldn't be added.

    Several different sources. The information about sprintf I've had in my head for some time and am not sure exactly when or where I discovered it. My 2nd edition Camel book mentions that sprintf formattiong codes work the same way in Perl as in C, but somewhere along the line I believe I have been told by someone that this was present in Perl4. As far as arrays not interpolating in older versions of Perl, I picked this up when I was new, by trying this:

    print "jonadab@bright.net";

    In Perl 5.0 through 5.6, this will give you an error, telling you that the @ symbol needs to be escaped; in 5.8, it no longer does this (though if you use warnings you will get a "Possible unintended interpolation" warning). But in 5.0 this behavior was new, and so the error message was included so people would know what was going on when they got "jonadab.net" and wondered where the rest of their email address went. The information about Perl6 mostly comes from reading the Apocalypse articles and to a lesser extent the perl6-language mailing list. I think I may also have picked up from the Perl6 sources the idea that hash interpretation was not possible in Perl5 because it would conflict with the sprintf syntax, or I may have figured that out on my own. If you think about it, it's obvious that if printf "%02d", 3 gives you "03", then it can't also interpolate the hash named %02d. But in Perl6, printf will be handled another way, or such is my understanding, based on Apocalypse 2.


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