Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re^2: Confused as to why the "casting context" is mis-behaving

by thargas (Chaplain)
on Oct 20, 2010 at 13:02 UTC ( #866315=note: print w/ replies, xml ) Need Help??


in reply to Re: Confused as to why the "casting context" is mis-behaving
in thread Confused as to why the "casting context" is mis-behaving

Hmm. Please point to documentation. Your description of what's happening jibes with what we see, but I had the same impression as the original poster, i.e. that this was not the way it would work.

If there is no documentation, and I couldn't find any, then there needs to be. I'm not sure where to put it though. I looked in perlop under comma and perldata under slices.

In fact, under perltrap, I found:

? Comma operator in scalar context gives scalar context to args The comma operator in a scalar context is now guaranteed to give scalar context to its arguments. @y= ('a','b','c'); $x = (1, 2, @y); print "x = $x\n"; # Perl4 prints: x = c # Thinks list context interpolates list # Perl5 prints: x = 3 # Knows scalar uses length of list
Which I would take to be documentation to the contrary.

I'm confused.


Comment on Re^2: Confused as to why the "casting context" is mis-behaving
Download Code
Re^3: Confused as to why the "casting context" is mis-behaving
by tinita (Parson) on Oct 20, 2010 at 13:38 UTC
    from perlop:

    Comma Operator
    Binary "," is the comma operator. In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value. This is just like Cís comma operator.

    In list context, itís just the list argument separator, and inserts both its arguments into the list. These arguments are also evaluated from left to right.

Re^3: Confused as to why the "casting context" is mis-behaving
by ig (Vicar) on Oct 20, 2010 at 16:31 UTC

    This is documented in perldata, though maybe not as clearly or concisely as one might hope.

    The first issue is whether a slice is a list or not, ruling out the possibility that it is an array.

    This isn't stated clearly, as one might hope, in Slices. In that section it is, at best, only hinted at by statements like:

    A slice accesses several elements of a list, an array, or a hash simultaneously using a list of subscripts. Itís more convenient than writing out the individual elements as a list of separate scalar values.

    and

    Since you can assign to a list of variables, you can also assign to an array or hash slice.

    Perhaps the closest this section comes is:

    Since you can assign to a list of variables, you can also assig +n to an array or hash slice. @days[3..5] = qw/Wed Thu Fri/; @colors{'red','blue','green'} = (0xff0000, 0x0000ff, 0x00ff00); @folks[0, -1] = @folks[-1, 0]; The previous assignments are exactly equivalent to ($days[3], $days[4], $days[5]) = qw/Wed Thu Fri/; ($colors{'red'}, $colors{'blue'}, $colors{'green'}) = (0xff0000, 0x0000ff, 0x00ff00); ($folks[0], $folks[-1]) = ($folks[-1], $folks[0]);

    But this only states the exact equivalence in the case of assignment to a slice. It doesn't state that there is an exact equivalence in all cases.

    There are other indications. In Context one finds (emphasis mine):

    or slice, which is just a list anyway)

    And in Variable names one finds:

    @days[3,4,5] # same as ($days[3],$days[4],$days[5]) @days{'a','c'} # same as ($days{'a'},$days{'c'})

    So, perldata does not clearly, concisely and definitively state that slices and lists are equivalent in the obvious place (Slices), but none the less,if one reads carefully, I think this is the conclusion one would come to.

    If one accepts that a slice is equivalent to a list, then this leaves the question of what a list evaluates to in scalar context.

    In Scalar values one finds (emphasis mine):

    If you evaluate an array in scalar context, it returns the length of the array. (Note that this is not true of lists, which return the last value, like the C comma operator, nor of built-in functions, which return whatever they feel like returning.)

    The Note about lists is equivalent to the statement: If you evaluate a list in scalar context, it returns the last value, like the C comma operator.

    Thus we have the two relevant facts documented, more or less:

    • A slice is a list
    • A list, evaluated in scalar context, returns the last value

    These together predict the observed behavior.

    The quote from perltrap is interesting but I don't find it inconsistent with any of the above. It really should be covered under Context. They take care to state the context of the righthand side in the case of assignment to a list, but don't cover this less obvious case.

      You don't find the quote from perltrap interesting? Not even the fact that they have effectively the same assignment (from a list to a scalar) and claim that the result will be the length of the list? I.E. that note in perltrap is wrong, at least for those versions of perl that I have access to.

      I do find that interesting because that's the first documentation I found when looking for what the documented behaviour would be. My method was look to grep perltoc for slice and context and then look in the pages it pointed at.

      If this isn't going to be documented under the docs for slice (IMHO the correct place), then the other places need to be correct. Or we'll have people reporting bugs because they can't find the correct documentation.

        The example from perltrap is unfortunately ambiguous.

        Not even the fact that they have effectively the same assignment (from a list to a scalar) and claim that the result will be the length of the list?

        No, it doesn't get the length of the list (literal). It gets the length of the array, which is the last expression in the list literal. The last word of the example is worse than ambiguous, it is misleading. One can argue that it isn't technically incorrect because $x does get assigned the length of the list of scalar values currently in the array, @y. But it certainly looks incorrect if you view it through the broken lens of the false dichotomy of "array vs list".

        I.E. that note in perltrap is wrong, at least for those versions of perl that I have access to.

        If you run the provided code in your copy of Perl 5 the output is not the documented "x = 3"? If so, then you should file a bug report.

        The example would not be ambiguous if slightly modified:

        Comma operator in scalar context gives scalar context to args

        The comma operator in a scalar context is now guaranteed to give scalar context to its arguments.

        @y= ('a','b','c','d'); $x = (1, 2, @y); print "x = $x\n";

        Perl4 prints: x = c # Thinks list context interpolates list

        Perl5 prints: x = 4 # Knows scalar uses length of array

        This illustrates why I said "be careful how you define 'item'". A list literal can be said to return its last "item" in scalar context. But it is much more accurate to say that a list literal in a scalar context calls the last expression in scalar context and returns (just) that result. A list literal is a syntax construct so "last item" means the last expression, whatever appears after the last literal comma in that part of the source code.

        A list literal can return a list of scalar values. But the last value of that list of values is not always the same as the "last item" that the list literal returns in scalar context. This further proves that a list literal is not the same as a list of scalar values.

        A slice in scalar context actually does return the last value. A list literal returns the scalar value of the last expression. The perltrap excerpt illustrates the difference.

        - tye        

        But I do find it interesting, as I said.

        In fact, that example led me to a much more correct understanding of what is happening. I wasn't aware of it and would never have looked for such insight into how literal lists behave in perltrap, so thank you for pointing it out.

        I agree that what you found in perltrap should be presented elsewhere. I had said Context but on further consideration I think List value constructors would be a better place. There is already an example with a scalar variable as the last "value" (using the terminology in List value constructors, though I wonder if that is the best terminology) in the literal list. I think the example from perltrap would be a fine addition to that section.

        I do think there are faults in the example in perltrap. I get the same result described with the version of perl5 I have tested with. I don't have any perl4 handy to test that prior behavior with.

        The description in perltrap is inconsistent with perl 5.10.0 that I have recently been testing with. The description says:

        The comma operator in a scalar context is now guaranteed to give scalar context to its arguments.

        Consider:

        print "Scalar assignment:\n"; $x = ( context(1), context(2), context(3) ); print "\$x = $x\n\n"; print "List assignment:\n"; @x = ( context(1), context(2), context(3) ); print "\@x = @x\n"; sub context { my $arg = shift; if(wantarray) { print "$arg: list context\n"; return("oranges", "lemons"); } elsif(defined(wantarray)) { print "$arg: scalar context\n"; return("apples"); } else { print "$arg: void context\n"; return("into the..."); } }

        Which produces:

        Scalar assignment: 1: void context 2: void context 3: scalar context $x = apples List assignment: 1: list context 2: list context 3: list context @x = oranges lemons oranges lemons oranges lemons

        So, the example says the comma operator is guaranteed to give scalar context to its arguments when evaluated in scalar context, but in perl 5.10.0 I see void context in some cases.

        This raises yet another issue: what does the comma operator (or any operator) do in void context?

        perlop says the comma operator is left associative. I take this to mean that ( 1, 2, 3 ) is the same as ( ( 1, 2 ), 3 ) rather than ( 1, ( 2, 3 ) ). If I am correct, one description of the comma operator that is consistent with my observations would be:

        In scalar context, the comma operator evaluates its left argument in void context and discards any result then evaluates its right argument in scalar context and returns the resulting scalar.

        In void context, the comma operator evaluates both its arguments in void context and returns nothing.

        But, I haven't looked at the internals of perl, and this may be more of the nonsense that so frustrates tye.

        While tye said the comment at the end of the example you quote is misleading, I would go further and say it is wrong. It should say (IMHO) "Knows scalar uses length of array", as tye said. The ambiguity is, I think, in which "list" is referred to in the last comment in the example. The comment is correct if one considers it to refer to the list of values in the array @y, but incorrect if one considers it to refer to the literal list ending with @y.

        More than reporting bugs, most people will continue to produce nonsense descriptions and explanations if this isn't better documented. This will lead to many surprises, which Perl/perl is supposed to avoid. In this case, I think better documentation is the most pragmatic means to reducing the element of surprise.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://866315]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2014-09-30 23:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (386 votes), past polls