in reply to Re^4: Scalar context of slice (myth)
in thread Scalar context of slice
Hm. Seems to me that a list in a scalar context does return the last item:
print scalar (1,2,3);; Useless use of a constant in void context at (eval 18) line 1, <STDIN> + line 16. 3
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.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^6: Scalar context of slice ("list")
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 | |
So whether an op returns a list or not depends on whether it creates a list internally? It doesn't makes sense to describe the result of a function using different terminology based on whether it builds a list internally or not in order to return that result. For example, say grep built a list on the stack even in scalar context in an old version of Perl. According to what you said, that grep returns a list in scalar context. That means grep returns a list in scalar context in one version of Perl but not in others, despite returning the number of unfiltered elements in both.
Yes, cause it commonly fails. In the aforementioned version of grep, grep results in a list. And a list in scalar context will return... the last element of the grep? No, it didn't. | [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Oct 04, 2008 at 10:22 UTC | |
by ikegami (Patriarch) on Oct 04, 2008 at 11:35 UTC | |
by tye (Sage) on Oct 06, 2008 at 03:50 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: Um, the second "..." above was "(at least some versions of Perl)" so showing source code for some other version of Perl isn't much of a counter argument. Exactly which versions of Perl was even noted elsewhere in this thread in reply to you. So are you arguing that grep used to return a list so it used to give the last item in scalar context? Or are you arguing that grep was designed to not return the last item because it was known that one day grep would be optimized to no longer "return a list"? Or are you going off on some tangent unrelated to my point, which is that it makes no sense to claim that a slice returns the "last item" because "a slice returns a list and a list ..."? That is, there is, in fact, no general "just return the last item of the list" code in Perl. I'm not sure what you are talking about. I don't see where you show code that does the "take the last item of a list" for any construct that "returns a list", such as for the three different types of slice. If there were such code, then there would have been no need for me to patch one of those slice forms to add yet another copy of the code that takes the last item (and Perl wouldn't have dumped core). Despite Perls' celebration of TIMTOWTDI, it has become derigour to only accept one abstract description of many of those affects. Whatever. I'm not arguing for some "one true" abstraction. I've often argued for the opposite and several places in the node that you replied to I mention multiple ways of describing things. There doesn't have to be only "one true" abstaction for me to point out that "a slice returns a list therefore it ..." is a bizarre rationalization. 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? Yes, they both (in recent versions of Perl) produce an intermediate list of scalar values on the stack (which is often called just "list" but is also certainly not the same thing as the "list literal" construct, as evidenced by your own sentence). And that all but the last element of that stack-held list of scalars are then discarded when in a scalar context? No, not in the least. The code that selects the last item of the list (of scalar values on the stack) for a list literal is completely separate from the three versions of that code that exist for the three types of slices (hash slices, array slices, and list slices)1. It is trivial to make a version of Perl where a hash slice in scalar context returns the number of items, an array slice in scalar context returns the first item, and a list slice in scalar context does something else. There are 4 different pieces of code representing four different design decisions (or, for most of those, more like "non-decisions", I expect, especially since I wrote one and made no design decision when doing so). 1 See the bottom of pp_aslice(), the bottom of pp_hslice(), and the middle of pp_lslice() all (probably) in pp.c for 3 of those four separate checks against GIMME.
Just as the code for grep (in older versions of Perl) that selects a count (after pushing a list onto the stack) was separate. If your argument made sense, then surely grep in Perl prior to 5.010 would also have to return the last item 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. I never objected to using simply "list" in places2. Now, if one tried to make a proclamation "I've boiled the kettle and driving while boiled is likely to make the coppers boiled, therefore if the kettle drives it will be a police officer" switching between three different meanings of "boiled" in the same sentence, few would be convinced. 2 Now, it is best to make clear more precisely what you mean by "list" in that particular context. And it is important for readers of text about Perl to realize that "list" can mean quite a few different things. Without those two conditions, we get things like a SoPW node asking about writing [('a','b','c')] in a regex because the documentation says you put a "list of characters" between the brackets (true story, though I couldn't think of a likely strategy for finding it with a reasonable amount of time/effort, so I didn't look and it was many years ago so the details are surely imperfectly remembered). Similarly, it makes no sense to use two (or even three) different definitions of "list" in an argument "X is a 'list', a 'list' does Y, therefore X does Y". 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. Strawman. I simply say "a slice in scalar context returns the last item". If somebody asks "why?", then I certainly don't say "because it is a list, not an array". Further, when I've seen other people claim that or hear it claimed, I've often also seen them later tripping over the misconceptions involved. Otherwise it would just be a semantic argument and not something I'd find worth wasting much time or effort on. And, yes, a simple but wrong explanation of "why?" is worse than a correct explanation of "why?" whether it is simpler or more complex. Simply "because that was the way Perl was built" is a reasonable answer. I've certainly never written the horrid explanation that you offered as the strawman alternative. 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. I wrote above that "there is no such thing as 'a list in scalar context'" "is actually an incorrect statement". Though, I've never noticed it being "oft-made" regarding comma operators. Nor do I find it "abstractly absurd". - tye | [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Oct 06, 2008 at 08:25 UTC | |
by ikegami (Patriarch) on Oct 06, 2008 at 09:26 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 | |
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. s/grep/a slice/g above and it all is precisely as true as it was before the substitution. 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. Swap "grep" with "a slice" with each other above and it is just as true: I fail to see how the scalar return value from a slice when called in scalar context is equivalent to the list returned by grep. To be fair to FunkyMonk, there was nothing said about everything that can in any circumstance always returning the list last item of a list it took as an argument in scalar context. Yes, but s/said/implied/ and then you'd be dead wrong. What was said was that "X returns Y and Y does Z" as explanation of for why "X does Z". That only makes logical sense if "X returns Y" implies that "X does Z" which only makes sense if the "Y does Z" phrase really meant "Y always does Z" or "every Y does Z". And it makes even less sense when this is adjacent to the mention of how W if different and it is pretty clear that "W returns Y" in exactly the same sense as "X returns Y". You seem to hold the mistaken impression that a slice (any of the three types of slice) is fundamentally different from grep and map. Each type of slice only returns a list when in list context and each type of slice makes a(n independent) choice about what to return when in scalar context, exactly like grep and map. (And the optimization done to map and/or grep with Perl 5.010 certainly has nothing to do with what anything chooses to return in scalar context.) - tye | [reply] [d/l] [select] |
by mr_mischief (Monsignor) on Oct 08, 2008 at 18:25 UTC | |
by tye (Sage) on Oct 08, 2008 at 20:23 UTC | |
| |
|
Re^6: Scalar context of slice (myth)
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] |
|
Re^6: Scalar context of slice (myth)
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 | |
Your right that a single operator is created for the entire string of commas. Your snippet doesn't prove that, but -MO=Concise does.
But the list operator doesn't return a list in scalar context. No reduction occurs, default or otherwise.
It's the builtin or operator that makes the choice, not the context. | [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Oct 04, 2008 at 04:35 UTC | |
by JavaFan (Canon) on Oct 04, 2008 at 14:38 UTC | |
You left of binary. The latter comma in doesn't have an operand on its right hand side, so it cannot be a "binary comma". In Perl, there isn't something like an "empty statement (or expression)" which would return 'undef'. If there was, then wouldn't return 1, but undef or null or nothing. | [reply] [d/l] [select] |