Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re^2: If you believe in Lists in Scalar Context, Clap your Hands

by gone2015 (Deacon)
on Oct 24, 2008 at 01:43 UTC ( [id://719217]=note: print w/replies, xml ) Need Help??


in reply to Re: If you believe in Lists in Scalar Context, Clap your Hands
in thread If you believe in Lists in Scalar Context, Clap your Hands

The difference you point out between:

my $r1 = ( print_context(), print_context() ); # Void # Scalar my $r2 = sub { ( print_context(), print_context() ) }->(); # Scalar # Scalar
is amusing -- not quite as consistent as I thought.

Now, some questions for you:
in List Context there are a number of things which make lists, including:
....

How come array slices and hash slices are in that list, but not arrays and hashes?

Why aren't any named operators (such as grep and map) in that list?

OK. The list was things that make lists, which are the problematic things Scalar/List context-wise. At that point I was summarising what had been discussed so far... I went on to subroutines and named operators. Sorry if that was less than clear.

what's wrong with the notion of a List in Scalar Context ?
Given that an array returns a list in list context, how do you place that list in scalar context?

I would argue that, when treated as an rvalue, this is the key difference between a list and an array. Since in Scalar Context the value of the array isn't the list, the case does not arise.

I understand that it can also be argued that in Scalar Context there are no lists... however much it looks as though there might be.

That the value of @array depends on the Context is one thing to understand. That ($a, $b, $c) or @z[@p] are or are not lists, depending on the Context, seems to me to be harder to get to grips with, and unnecessary.

Finally, an answer to your question:
BTW: I'm gagging to know how to describe why this:
$r = () = 1..27 ;
A list assignment ("() = 1..27") in scalar context ("$r =") evaluates to the number of elements to assign.

Ah. I had expected the second, scalar assignment, to operate on the result of the first assigment. I have now found the place in the book where, by definition, a scalar assignment to the left of a list assignment gets the number of items to the right of the list assignment, not the number of items successfully assigned in that list assignment. (Well, that's clear to me now !)

Thank you. Perl, eh :-)

Finally, and for extra points (and points mean prizes), how does one describe the difference between a list and an array ?
An array is variable. A list is a piece of code that generates a list operator.
A list is the operator generated from a list in the code.
A list is the result of an operator or function in list context.

OK. Well, everybody avoided mentioning the influence of Scalar Context on arrays. But then if lists can only exist in List Context, that wouldn't be worth mentioning :-)

Replies are listed 'Best First'.
Re^3: If you believe in Lists in Scalar Context, Clap your Hands
by ikegami (Patriarch) on Oct 24, 2008 at 02:23 UTC

    The list was things that make lists, which are the problematic things Scalar/List context-wise. At that point I was summarising what had been discussed so far...

    But you had discussed arrays and hashes. Are you implying that array slice make lists and arrays don't?

    The omission seems rather "convenient" because it allowed you to cut two exceptions from the "in Scalar Context" list.

    Given that an array returns a list in list context, how do you place that list in scalar context?

    I would argue that, when treated as an rvalue, this is the key difference between a list and an array. Since in Scalar Context the value of the array isn't the list, the case does not arise.

    Exactly. A list can't be produced in scalar context. So how can a list be put into scalar context?

    The point of the question was to point out that "list" is an overloaded term. "List in scalar context" is deceptive, misleading and/or confusing.

    Ah. I had expected the second, scalar assignment, to operate on the result of the first assigment.

    Assignment operators are right-associative. That means that in chain of assignments, the right-most has highest precedence. ** is also right-associative.

    >perl -le"print( 2**3**4 )" 2.41785163922926e+024 >perl -le"print( (2**3)**4 )" 4096 >perl -le"print( 2**(3**4) )" 2.41785163922926e+024

    OK. Well, everybody avoided mentioning the influence of Scalar Context on arrays.

    Two of the three types of list I mentioned in my answer can't be put into scalar context. That makes it a rather minor difference.

      But you had discussed arrays and hashes. Are you implying that array slice make lists and arrays don't?

      Yes. I'd say that an array is a variable whose value is a list. Using the name or some other reference to an array yields that value or its length, depending on Context. In that sense, yes, I was implying that arrays do not make lists. A slice operation, on the other hand, takes a list value and makes a list which is a subset. (I'm open minded, though: if there is, in fact and invisible operator that makes lists out of arrays I would not be surprised.)

      The omission seems rather "convenient" because it allowed you to cut two exceptions from the "in Scalar Context" list.

      I'm sorry you've drawn that conclusion.

      The last item in the list you refer to covers the case of arrays, pointing out that lists and arrays are not identical, and notes the effect of Context. For completeness I could have mentioned hashes, but their relationship to lists is, in my opinion, one step removed, and I did try to keep to the main point, namely Lists in a Scalar Context.

      Exactly. A list can't be produced in scalar context. So how can a list be put into scalar context?

      Just for a moment, let's consider integers and floats as two different sorts of value. Suppose we have the expression:  27 % 4.79. Now, '%' is an integer operation -- one could say it has "Integer Context" -- and the floating point argument is implicitly coerced to an integer, suitable for the '%' operation. At least that is a common understanding of what happens.

      You may argue that the thing which I referred to as a floating point value never was a such, because you cannot have a "Float in Integer Context". That would be consistent with the view that, in Scalar Context:  100 + @r[@p] the thing which looks a lot like a list isn't a list because you cannot have a "List in Scalar Context" (QED).

      "List in scalar context" is deceptive, misleading and/or confusing.

      It is definitely dangerous to assume that all things that return lists in list context will have "List in Scalar Context" semantics. Just as it is would be dangerous to assume that all numeric functions return the same sort of number. So one has to be careful.

      However, where those semantics apply, which is not uncommon, I find it a less confusing notion than "it was never a list, no matter what it looks like". Cooercion is a well understood and common notion. I really don't see why it should not apply to lists. (It does to arrays.)

      Assignment operators are right-associative. That means that in chain of assignments, the right-most has highest precedence. ** is also right-associative.
      >perl -le"print( 2**3**4 )"
      2.41785163922926e+024
      

      Thanks for the clarification. The right-hand '**' happens first, giving 81, then the left-hand '**' takes the 2 and the 81, giving a modestly big result. OK.

      Following that model, in:  $r = ($a, $b) = 0..11 ; the right-hand assignment:  ($a, $b) = 0..11 happens first, so we get ($a=0, $b=1), then that is assigned to $r.... leaving to one side whether ($a, $b) is or isn't a list (given that for the right-hand assignment there's List Context, and in the left-hand one Scalar Context).... since the result is $r=12, right-associativity doesn't appear to be the whole story.

      With thanks to all who pointed me in the right direction here, this is a piece of deeper magic. The right-associativity causes the 0..11 to be evaluated in List Context, and a list assignment is made to ($a, $b). So far, so straightforward. The interesting bit is that the next (left hand), scalar assignment, effectively reaches round the first (right hand) assignment and picks up the length of the list. This is well documented, but the significance of it didn't sink in when I read it however many years ago.

      It's obvious to me now, of course. We're all used to using this magic, for example in: while (my($k, $v) = each(%h)). I admit that I had assumed that this was either because the assignment would leave the lvalue with no more entries in it than were available in the rvalue, or because the $v was undefined -- though I never tested either. I live and learn. (Though, sadly, wisdom eludes me.)

      Ah well. It has been said that "There is no spoon". But some say it's worse than that (Jim), by extension there's no cutlery, no kitchen utensils, no stove, no kitchen and pretty soon I can expect to starve to death. I think I'll go and do something really dangerous now, I'll take away some brackets and to blazes with the sign.

        Are you implying that array slice make lists and arrays don't?

        Yes.

        How do you reconcile that with the fact that both the array and the array slice perform exactly the same action in list context: they put their members on the stack. Either they both make a list or neither does.

        Following that model, in: $r = ($a, $b) = 0..11 ; the right-hand assignment: ($a, $b) = 0..11 happens first, so we get ($a=0, $b=1), then that is assigned to $r.... leaving to one side whether ($a, $b) is or isn't a list (given that for the right-hand assignment there's List Context, and in the left-hand one Scalar Context).... since the result is $r=12, right-associativity doesn't appear to be the whole story.

        I bolded the mistake. Just like the right-hand ** doesn't return 3 in 2**3**4, The right-hand assignment doesn't return ($a, $b) in $r = ($a, $b) = 0..11. A list assignment in scalar context returns the number of items it was given to assign. 12, in this case.

        >perl -le"print( scalar( ($a, $b) = 0..11 ) );" 12

        Just for a moment, let's consider integers and floats as two different sorts of value. Now, '%' is an integer operation -- one could say it has "Integer Context" -- and the floating point argument is implicitly coerced to an integer, suitable for the '%' operation. At least that is a common understanding of what happens.

        There are two different sort of value. Three even.
        NVs hold floats (which could technically be integers, but not relevant).
        IVs hold machine signed integers.
        UVs hold machine unsigned integers.

        I wouldn't say it has integer context, because that would imply a parallel with scalar vs list context. Scalar and list context force operands to returns a scalar and a list respectively. Integer coercion doesn't force operands to returns an integer.

        Let's look at an example. Given f() % 3, f() is executed in scalar context and in "integer context".

        Scalar ContextInteger Coercion
        The scalar context will force f() to return a scalar. The integer conversion doesn't force f() to return an integer.
        f() is unable to return a list. f() is free to return undef, a string, a reference, a float, etc.
        % never converts a list to a scalar. The conversion to integer is performed by %.
        The scalar context is forced onto the operands before they are evaluated. The integer coercion is performed on the operands after they are evaluated.

        Your argument relies on the premise of a parallel between scalar context and integer coercion, but it's very clear there isn't one. The premise is false, so the argument is moot.

        This isn't relevant, but I thought you'd be interested in an additional difference: some operators (such |, & and ^) behave differently based on whether they're given a string or an integer. Some operators behave differently based on the length of the list they are given, but you won't find an operator that can accept both a scalar and a list.

        Update: Formatting changes. Minor typo correction.

        Yes. I'd say that an array is a variable whose value is a list. Using the name or some other reference to an array yields that value or its length, depending on Context. In that sense, yes, I was implying that arrays do not make lists. A slice operation, on the other hand, takes a list value and makes a list which is a subset. (I'm open minded, though: if there is, in fact and invisible operator that makes lists out of arrays I would not be surprised.)
        No.

        An array returns a list in list context, but it isn't a list. Just as localtime() isn't a list, although it will return a list in list context. In fact, every expression will return a list in list context, although that list may be empty or just contain a single value.

        As for the slice operation, yes, it will take a subset of a list. On arrays though, it can return more.

        @a = ()[3, 5, 6]; @b = @c[3, 5, 6]; say 0 + @a; say 0 + @b; __END__ 0 3
        Following that model, in: $r = ($a, $b) = 0..11 ; the right-hand assignment: ($a, $b) = 0..11 happens first, so we get ($a=0, $b=1), then that is assigned to $r.... leaving to one side whether ($a, $b) is or isn't a list (given that for the right-hand assignment there's List Context, and in the left-hand one Scalar Context).... since the result is $r=12, right-associativity doesn't appear to be the whole story.

        With thanks to all who pointed me in the right direction here, this is a piece of deeper magic. The right-associativity causes the 0..11 to be evaluated in List Context, and a list assignment is made to ($a, $b). So far, so straightforward. The interesting bit is that the next (left hand), scalar assignment, effectively reaches round the first (right hand) assignment and picks up the length of the list. This is well documented, but the significance of it didn't sink in when I read it however many years ago.

        You are quite wrong here. The list assignment operator in scalar context DOES NOT RETURN A LIST. It returns the number of elements on its right hand side. It sets $a and $b as side-effects - it doesn't return its left hand side. If you think of operators being shorthands for function calls, you may read
        $r = ($a, $b) = 0 .. 11;
        more or less as
        sassign(\$r, scalar lassign([\$a, \$b], range (0, 11))) sub lassign { my ($rhs, $lhs) = @_; for (my $i = 0; $i < @$rhs; $i ++) { $$rhs[$i] = $$lhs[$i]; } wantarray ? map {$$_} @$lhs : scalar @$rhs; } sub sassign: lvalue { my ($rhs, $lhs) = @_; $$rhs = $lhs; $$rhs; }
        Now the above isn't exactly the same in the your line in detail, because I don't think you can mimic the assignment operator exactly in Perl code, but you get the idea.

        The point is, the assignment is a side-effect. The results are not returned. And also important, there's no magical reaching around by the first (leftmost) assignment. The first assignment operator doesn't look on its right hand side and say "my, my, lets see, I've a list here, I wonder how that list came to be. Oh, I see, in the past this list was created by an assignment. Let me reach even further back in the past, and see how many elements there were on its right hand side". No, by the time the leftmost assignment gets in the driver seat, it'll see two operands, a scalar lvalue, and a scalar value. How that scalar value got there doesn't interest the assignment operator. It could have been the return value of the add operation, or the return value of the lassign operator.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2024-04-26 07:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found