Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

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

by JavaFan (Canon)
on Oct 24, 2008 at 12:26 UTC ( #719331=note: print w/ replies, xml ) Need Help??


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

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.


Comment on Re^5: If you believe in Lists in Scalar Context, Clap your Hands
Select or Download Code
Re^6: If you believe in Lists in Scalar Context, Clap your Hands
by oshalla (Deacon) on Oct 24, 2008 at 15:49 UTC
    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.

    A flat "No". Goodness.

    I'm puzzled by what you are contradicting here. Is it controversial to say that an array is a variable ? Is it then controversial to say the the value of that variable is a list ? Or to note that in an expression, the part of the value used (the list itself or its length) depends on the Context, is that controversial ?

    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

    Well, that's amusing. I note that it doesn't matter whether @c is undefined or defined but empty. So, slices of lists are different from slices of arrays. Splendid. Thank you.

    (I realise also that subset might be the wrong word, since a slice can also include repeated values, which might not pass as a subset. Also, as you point out, some items in the slice may be undef, which may or may not be considered as part of the original.)

    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.

    SO IT WOULD APPEAR.

    I was trying to say: to fully understand $r = ($a, $b) = 0..11;   it is necessary to know what a many-splendored thing '=' is. Understanding the more common-place notion of right-associativity is not enough. I'm sorry if that wasn't as clear as I had hoped.

    I do not know how this is actually implemented. I can see how the documentation describes it. The effect remains as if the scalar assignment reaches round the list assignment, but I am more than happy to take your word for it that it doesn't actually work like that.

    Further, I withdraw unreservedly any implication, imputation or suggestion that this (or any other) mechanism in Perl might, through a glass darkly, or otherwise, appear to be magical to even the slightest degree. I throw myself on the mercy of the court, and hope, as only a true penitent can hope, for a light sentence involving the minimum of pain, and if at all possible, no permanent disfigurement.

      Understanding the more common-place notion of right-associativity is not enough.
      Indeed. You must also know the return value of the operator (= in this case). But that's the same as trying to understand the result of
      2 ** 3 ** 4
      you need to understand the return value of ** beside understanding right-associativity.
      I do not know how this is actually implemented.
      Associativity is a parser/compiler issue. By the time the code is running, associativity no longer plays a role. As for the implementation of assignment, they are actually two different operators, scalar assignment (pp_sassign in pp_hot.c) and list assignment (pp_aassign in pp_hot.c).

      And if you look in pp_hot.c, you see there's check on context to determine what is returned:

      if (gimme == G_VOID) SP = firstrelem - 1; else if (gimme == G_SCALAR) { dTARGET; SP = firstrelem; SETi(lastrelem - firstrelem + 1 - duplicates); } else { if (ary) SP = lastrelem; else if (hash) { if (duplicates) { /* Removes from the stack the entries which ended up a +s * duplicated keys in the hash (fix for [perl #24380]) + */ Move(firsthashrelem + duplicates, firsthashrelem, duplicates, SV**); lastrelem -= duplicates; } SP = lastrelem; } else SP = firstrelem + (lastlelem - firstlelem); lelem = firstlelem + (relem - firstrelem); while (relem <= SP) *relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef; } RETURN;
      Now, I don't expect you to understand everything (neither do I), but I do hope you see that in VOID context, nothing is returned, in SCALAR context, a single value is returned, and in LIST context, more things are returned.

      One more piece of evidence that it isn't the scalar assignment that is reaching all the way behind, here we have a list assignment in scalar context where the scalar context isn't given by another assignment:

      $ perl -E 'say scalar(() = ($a, $b, $c))' 3 $
        One more piece of evidence that it isn't the scalar assignment that is reaching all the way behind, here we have a list assignment in scalar context where the scalar context isn't given by another assignment:

        If you can't have a list in a scalar context, how can you have the assignment of a list in scalar context? You have even said in this thread that lists don't even exist.

        To pick your own nit, perhaps you meant "the result of the list assignment operator upon assigning a series of scalars to an empty series of scalars".

        It's very difficult for there to be a list assignment in scalar context there if lists don't exist. What does a "list assignment" assign? It's also very difficult to support the idea that lists don't exist when you show the code that returns multiple scalars ("atoms" and references to other complex structures) in order (a "list") in LIST context with variables named 'lelem' and similar. The "elem" part of those clearly stands for "element". Elements of what?

        You can argue that there is another, clearer concept to use to understand this topic. It's very difficult to support the idea that the concept used in the documentation, the source code, the tutorials, and the in concepts and culture of other programming languages from which Perl borrows ideas does not exist in Perl, though. Call it flawed if you like, but saying it doesn't exist is inaccurate.

      Further, I withdraw unreservedly any implication, imputation or suggestion that this (or any other) mechanism in Perl might, through a glass darkly, or otherwise, appear to be magical to even the slightest degree.
      Now that's worth an upvote :)

      FWIW, I took the "flat No" as applying to "arrays do not make lists".

Re^6: If you believe in Lists in Scalar Context, Clap your Hands
by ysth (Canon) on Oct 28, 2008 at 05:55 UTC
    A slight correction. The difference you note between list slices and array slices is in fact only there in some cases:
    @a = ()[0,0,0]; @b = @c[0,0,0]; @c = (1)[0,0,0]; say 0 + @a; say 0 + @b; say 0 + @c; __END__ 0 3 3
    The rule is that a list slice (in list context) produces an empty list if all the indices are out of range. This permits code like this:
    if ( my ($dev,$ino) = (stat(FH))[0,1] ) {
    where the error condition is "passed through" the slice and assignment to affect the if.

    In all other cases, a list slice behaves just like an array slice.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2014-12-29 05:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (184 votes), past polls