in reply to Re^6: Scalar context of slice ("list")
in thread Scalar context of slice
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:
PP(pp_grepwhile) ... if (gimme == G_SCALAR) { // Scalar context dTARGET; XPUSHi(items); // Choose the scalar that gets returned. } else if (gimme == G_ARRAY) SP += items; RETURN; } ...
That is, there is, in fact, no general "just return the last item of the list" code in Perl.
c:\test>perl -MO=Concise -wle"print scalar( 1, 2, 3 );" Useless use of a constant in void context at -e line 1. 8 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 7 <@> print vK ->8 3 <0> pushmark s ->4 - <1> scalar sK/1 ->7 6 <@> list sK ->7 <<< And yet, there it is. 4 <0> pushmark v ->5 - <0> ex-const v ->- - <0> ex-const v ->5 5 <$> const[IV 3] s ->6 -e syntax OK
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:
c:\test>perl -wle"print for ( 'a','b','c' )" a b c
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:
c:\test>perl -wle"print for scalar(( 'a','b','c' ))" Useless use of a constant in void context at -e line 1. Useless use of a constant in void context at -e line 1. c
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:
c:\test>perl -wle"print for scalar 'a','b','c'" a b c c:\test>perl -wle"@a = (1,2,3); print for @a" 1 2 3 c:\test>perl -wle"@a = 1,2,3; print for @a" Useless use of a constant in void context at -e line 1. Useless use of a constant in void context at -e line 1. 1
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:
PP(pp_aslice) { dSP; dMARK; dORIGMARK; register AV* const av = (AV*)POPs; register const I32 lval = (PL_op->op_flags & OPf_MOD || LVRET); if (SvTYPE(av) == SVt_PVAV) { const I32 arybase = PL_curcop->cop_arybase; if (lval && PL_op->op_private & OPpLVAL_INTRO) { register SV **svp; I32 max = -1; for (svp = MARK + 1; svp <= SP; svp++) { const I32 elem = SvIVx(*svp); if (elem > max) max = elem; } if (max > AvMAX(av)) av_extend(av, max); } while (++MARK <= SP) { register SV **svp; I32 elem = SvIVx(*MARK); if (elem > 0) elem -= arybase; svp = av_fetch(av, elem, lval); if (lval) { if (!svp || *svp == &PL_sv_undef) DIE(aTHX_ PL_no_aelem, elem); if (PL_op->op_private & OPpLVAL_INTRO) save_aelem(av, elem, svp); } *MARK = svp ? *svp : &PL_sv_undef; } } if (GIMME != G_ARRAY) { MARK = ORIGMARK; *++MARK = SP > ORIGMARK ? *SP : &PL_sv_undef; SP = MARK; } RETURN; }
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.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^8: Scalar context of slice ("list")
by ikegami (Patriarch) on Oct 04, 2008 at 09:20 UTC | |
by BrowserUk (Patriarch) on Oct 04, 2008 at 10:22 UTC | |
by ikegami (Patriarch) on Oct 04, 2008 at 11:35 UTC | |
|
Re^8: Scalar context of slice ("list")
by tye (Sage) on Oct 06, 2008 at 03:50 UTC | |
by BrowserUk (Patriarch) on Oct 06, 2008 at 08:25 UTC | |
by ikegami (Patriarch) on Oct 06, 2008 at 09:26 UTC | |
by BrowserUk (Patriarch) on Oct 20, 2008 at 02:12 UTC | |
by ikegami (Patriarch) on Oct 20, 2008 at 04:22 UTC | |
|