in reply to Re^3: Scalar context of slice (myth)
in thread Scalar context of slice
You said:
A slice returns a list and assigning a list to a scalar will just assign the last item in the list to the scalar.
And map and grep each return lists. So your above proclamation would imply that map and grep "will just assign the last item in the list to the scalar". So do you think that map doesn't return a list? Or do you retract your first sentence?
- tye
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^5: Scalar context of slice (myth)
by BrowserUk (Patriarch) on Oct 04, 2008 at 00:26 UTC | |
Hm. Seems to me that a list in a scalar context does return the last item:
And map and grep each return lists ... ...except, when they find their return context is SCALAR they chose not to return a list, but instead they return a scalar, which happens to be the size of the list they would have returned had they found themselves in a list context. ...except also when they find themselves in a void context, in which case they chose not to return anything at all. It mostly a matter of words, but I think it is wrong to say "map and grep each return lists", when like any other perl function they can chose whether to return a list, a scalar or nothing at all depending upon the context in which they are called. 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.
| [reply] [d/l] |
by tye (Sage) on Oct 04, 2008 at 06:12 UTC | |
You do a good job of showing how the meme is seductive. Thanks. Let's start with the original statement, verbatum, which is not picking on FunkyMonk since this is not even close to an unusual phrasing of the oft-repeated meme: A slice returns a list and assigning a list to a scalar will just assign the last item in the list to the scalar. That (somehwat implied) logical argument can be broken down into several pieces: Now, for item 3 to make logical sense, the meaning of item 2 must be stronger than how it might be interpretted on its own. So it would be clearer to upgrade item 2 via s/a list/any list/ and/or s/will/will always/. Hm. Seems to me that a list in a scalar context does return the last item: Certainly. It also seems to me that a slice returns a list. It also seems to me that grep, in precisely the same way, "returns a list". Therefore, it should seem to me that grep in scalar context returns the last item (but, of course, it doesn't). You (as has become quite typical, when people try to defend this flawed meme) make an argument about how you can claim that "grep doesn't really 'return a list'". But go ask some average Perl programmer you run into "Does grep return a list?". If they immediately respond "Well, not really", I'll be quite shocked. If they say as you did, "No, that is wrong", I'll be even more shocked. But if so, ask them if a slice returns a list. If they immediately respond "Oh, yes, of course, always", then they are clearly a figment of your imagination. :) A much better way to resolve the problems with this meme lies in quite a different direction (and thanks for also demonstrating that, even though I've gone over this many times over many years, there are no shortage of fine, very wise monks who appear to have missed it). So, back to our 3 statements. Consider "2) Assigning a list2 to a scalar will just assign the last item of the list3 to the scalar". As you so aptly demonstrated, what "list2" means here is better termed "list literal" or, perhaps more accurately but certainly more awkwardly termed "the use of the comma operator within parentheses". That is, the prototypical construct ('a','b','c'). Yes, a (any) "list literal" (often just referred to as just "a list" in many situations) certainly (always) returns some "last item" when used in a scalar context. So, in "1) A slice returns a list1", do we mean that a slice returns a "list literal"? Of course not! How could a slice "return a use of the comma operator"? You can't even argue that a hash slice gets compiled into the same code as ( $h['a'], $h['b'], $h['c'] ) does, simply because it doesn't. A slice returns a "list of scalar values" (at least when used in a list context). So "list1" means "a list of scalar values" (perhaps with some extra qualifiers, or perhaps not, depending on one's point of view and perhaps even on which version of Perl is being discussed, etc.). So "list1" and "list2" actually mean two quite different (but related) things. You certainly can't reasonably argue that "list1" means "list literal". But perhaps you want to argue the other direction, that is, to claim that "Assigning a list of scalar values to a scalar will just assign the last item of the list3 to the scalar". Well, that would certainly be rather awkward to argue. But I'll also note an extra wrinkle you'd trip over if you did try to do that. Consider the following:
We see that @list gets assigned a list of scalar values [namely, ( 'a', 'b', 3, 2, 1 )]. So, if "Assigning a list of scalar values to a scalar will just assign the last item of the list3 to the scalar", then surely $scalar gets set to the last item in that list of scalar values, namely 1. But no, $scalar gets set to "321". This is because "list2" means "list literal" and "list3" also doesn't mean "list of scalar values"; "list3" means "the list of expressions that have been separated by commas". What gets assigned to $scalar is the value of reverse(1..3), interpretted in a scalar context. reverse(1..3) is the last item in the list of expressions that were separated by commas. So what is true is that: A list literal (use of the comma operator within parentheses) in a scalar context returns the value of the last (comma-separated) expression, itself interpretted in a scalar context. Surely it is clear that this fact has very little to do with what a slice (array slice, hash slice, or list slice) returns in a scalar context. And that is why the quoted meme is seriously flawed (despite producing a correct prediction in the case of a slice -- and wrong predictions in cases including grep). Now, as for the competing meme that is used to counter the above meme, namely: "there is no such thing as 'a list in scalar context'"... I believe that it presents an important concept. Unfortunately, in an attempt to state this concept forcefully, it over-states it and thus is actually an incorrect statement. As you correctly pointed out, there actually are several cases where Perl produces a list of scalar values (on the stack) despite this production being done "in a scalar context". But these cases are still "the exception" more than "the rule". Perhaps a better phrasing of this competing meme would be (to paraphrase another famous phrase) "Perl abhors a list in a scalar context". Or, more clearly, "Perl rarely bothers to produce a list (of scalar values) when working in a scalar context". But slices and grep are both examples where Perl (at least some versions of Perl) will do exactly that: produce a list of scalar values (on the stack) despite that list being produced "in a scalar context". But we should also note that this "throw away most of the list and just return one scalar when confronted with a scalar context" is not automatic. The code to do that was missing for the case of a (hash(?)) slice prior to me submitted a patch many years ago. And Perl could dump core as a result. Every place that produces "a list in a scalar context" has to also have its own code added for taking care of throwing away most of the list. (Though Perl does defend itself against sloppy XS code, not requiring each XS function to take care of this situation itself.) That is, there is, in fact, no general "just return the last item of the list" code in Perl. There are several specific cases of such code (as well as several specific cases of code that returns something other than the last item). Finally, the moral of this story is: When you see 'list' being used in reference to Perl, it can mean any of quite a few different things. And this is despite the fact that "scalar", "scalar context", and "list context" are each pretty preciesly defined for Perl. And I didn't even mention that tr/.../.../ and regex character classes are each documented to use a "list" of characters and \w is even said to "generate a list". (: - tye | [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Oct 04, 2008 at 07:54 UTC | |
You ... make an argument about how you can claim that "grep doesn't really 'return a list'". ... But slices and grep are both examples where Perl ... will do exactly that: produce a list of scalar values (on the stack) despite that list being produced "in a scalar context". Actually, it is the source that make that argument:
That is, there is, in fact, no general "just return the last item of the list" code in Perl.
There are two important descriptions that can be applied to the affects produced by running a piece of code:
Despite Perls' celebration of TIMTOWTDI, it has become derigour to only accept one abstract description of many of those affects. The problem is that the "one true abstract description", neither accurately describes the reality of what and how things happen, nor even provides a consistent abstraction to explain the easily observable affects. The results of these "one true way"-isms, is that we are left with no acceptable way to talk about things, that we write every day. This ('a','b','c') is obviously, observably, more than one thing, because when we ask to print it:
When we place that thing that consists of more than one thing, in what I hope no one will dispute is a "scalar context", it produces a different result:
It (the thing) becomes; reduces to; produces; something different. A scalar value. So, it's just a matter of agreeing a name or terminology that we can use decribe that thing: - A set of scalars? Too many connuctations. - A collection of scalars? Likewise. - A string of scalars? Not good. - A comma-separated sequence of scalar values? Possible, but what about the parens? They are important! Without them that comma-separated sequence behaves entirely differently:
So, whatever you term ( 'a','b','c' ), it is affected by context. In a G_ARRAY context, it produces...um..itself really. And in a G_SCALAR context it results in a scalar 'c'. So, if ( 'a','b','c' ) is a 'list', then how do you describe putting that thing in a scalar context? Surely it is clear that this fact has very little to do with what a slice (array slice, hash slice, or list slice) returns in a scalar context. Now, I don't know about you, but this:
looks a lot like it pushes the sliced elements onto the MARKSTACK, (which is as good a definition of what a 'list' is in the full nitty-gritty description as I can think of), before deciding what the context is and then discarding all but the last element if it happens to be G_SCALAR. So, if a list literal in the source, becomes a 'list' when it is pushed into the stack, doesn't it hold that when the multiple scalars produced by slicing an array is pushed onto the stack, it also becomes a list? And that all but the last element of that stack-held list of scalars are then discarded when in a scalar context? Just as we say "I've boiled the kettle" not "I boiled the water in the kettle", with the subtle inaccuracy understood and glossed over. Or, "I flew to Rio" instead of "I boarded an airplane which flew to Rio". Is it such a "bad meme" to say: A slice results in a list. And a list in a scalar context will return the last element of the slice? Rather than: an array slice constructor pushes the selected element of the array onto the markstack and if that array slice constructor is used within the confines of a scalar context then the stack pointer will be adjusted leaving just the last element accessible. The oft-made observation that because of the scalar context, the comma operator reduces the thing (set of things, collection of things...) to a scalar before it ever became a list is both technically incorrect, and abstractly absurd. 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.
| [reply] [d/l] [select] |
by ikegami (Patriarch) on Oct 04, 2008 at 09:20 UTC | |
by BrowserUk (Patriarch) on Oct 04, 2008 at 10:22 UTC | |
| |
by tye (Sage) on Oct 06, 2008 at 03:50 UTC | |
by BrowserUk (Patriarch) on Oct 06, 2008 at 08:25 UTC | |
| |
by mr_mischief (Monsignor) on Oct 08, 2008 at 17:02 UTC | |
In the case of grep, you're not assigning a list to anything. What you're assigning to the scalar is the return value from grep, which will be a list in list context and a scalar in scalar context. I fail to see how the scalar return value from grep when called in scalar context is equivalent to the list returned by a slice. | [reply] |
by tye (Sage) on Oct 08, 2008 at 17:45 UTC | |
by mr_mischief (Monsignor) on Oct 08, 2008 at 18:25 UTC | |
| |
by jwkrahn (Abbot) on Oct 04, 2008 at 01:54 UTC | |
...except also when they [map and grep] find themselves in a void context, in which case they chose not to return anything at all. That is true as of Perl version 5.10 however in all previous verions they did "return" a list in void context. | [reply] |
by JavaFan (Canon) on Oct 04, 2008 at 01:04 UTC | |
No. There is no such thing as a list in scalar context. Lists can only exist in list context. What you have here: is the comma operator in scalar context. Of which man perlop says: 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.except, when they find their return context is SCALAR they chose not to return a list, but instead they return a scalar A feat not reserved for map and grep, but shared by every operator and function in Perl, including, without a single exception, all user defined functions. Anything that is in non-void scalar context will return exactly one value. And nothing will ever be returned in void context. It mostly a matter of words, but I think it is wrong to say "map and grep each return lists", when like any other perl function they can chose whether to return a list, a scalar or nothing at all depending upon the context in which they are called. You are mostly right. Except that a function or operator cannot chose whether to return a list, a scalar or nothing at all. It's the context that makes the choice - not the function. | [reply] [d/l] |
by BrowserUk (Patriarch) on Oct 04, 2008 at 02:22 UTC | |
No. There is no such thing as a list in scalar context. Lists can only exist in list context. What you have here: scalar (1, 2, 3); is the comma operator in scalar context. Of which man perlop says: 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. Sorry, but that is just (bad) semantics dreamed up (probably long after the fact), to try and explain what actually happens. Proof: If the comma operator. In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value..., then this should print undef or null or nothing, but it doesn't:
It's the context that makes the choice - not the function. Okay. I can agree with that. The function can only chose whether to attempt to return a list, or some more meaningful scalar than the default reduction of that list, that the scalar context would otherwise make. 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.
| [reply] [d/l] [select] |
by ikegami (Patriarch) on Oct 04, 2008 at 03:52 UTC | |
by BrowserUk (Patriarch) on Oct 04, 2008 at 04:35 UTC | |
by JavaFan (Canon) on Oct 04, 2008 at 14:38 UTC | |