Re: confusing list assignment tests
On Tue, Jul 28, 2009 at 09:24:40PM +0200, Moritz Lenz wrote: : sub W () { substr(eval('want'), 0, 1) } : ... : : # line 560: : { : my @a; : my @z = (@a[0] = W, W); : #?rakudo 2 todo 'want function' : is(@a, 'L','lhs treats @a[0] as list'); : is(@z[0], 'L', 'lhs treats @a[0] as list'); : ok(!defined(@z[1]), 'lhs treats @a[0] as list'); : } : : : This tests that : 1) both calls to want() are in list context : 2) @a[0] gets only the return value of the first call to W() : 3) @z[0] gets the same thing : 4) There's no item for @z[1] : : Somehow I think this test (and many similar tests) are dead wrong. : Here's why: : : Either it's parsed as '@a[0] = (W, W)' (list assignment), then @a should : get both elements, and so should @z. Not according to S03, at least by one reading. @a[0] as a scalar container only wants one item, so it only takes the first item off the list, and the list assignment produces a warning on the second because it's discarded. Since an assignment returns its left side, only one element is available to @z from @a[0]. : Or it's parsed as '(@a[0] = W), W' (item assignment), then the first : call should be in item context, and the second one in list context, and : @z should still get both items. It's not parsed like that, because only $x, $$xref, $($xref) and such are allowed targets for item assignment. Basically, it has to start with a $ sigil and not do anything fancy like subscripting. However, if you say @z = $x = $a, $b; it parses as @z = ($x = $a), $b and $b ends up in @z[1] but not in $x, which only gets $a. : Right? Or am I completely missing something important here? To get all the elements into $x you'd have to say @z = $x = ($a, $b); and @z[0] would be ($a,$b) with some type or other, whatever was returned by the parens, quite possibly Parcel (that is, List of Thunk or some such). : My current plan is to write such tests as : : sub l { 1, 2 } # return a short list : { : my @a; : my @z = (@a[0] = l(), l()); : is @a[0].elems, 4, '@a[0] = treats LHS as list' : is @z.elems,4, '... and passes all elements on the right'; : } : : Does this look sane, and match your understanding of assignment? Yes, but no. @z.elems and @a[0].elems should both be 1, I suspect. I wish we had a way of trapping and testing warnings too so we could see that 3 elements were discarded by the inner list assignment.. Larry
Re: confusing list assignment tests
Larry Wall wrote: Moritz Lenz wrote: : Either it's parsed as '@a[0] = (W, W)' (list assignment), then @a should : get both elements, and so should @z. Not according to S03, at least by one reading. �...@a[0] as a scalar container only wants one item, so it only takes the first item off the list, and the list assignment produces a warning on the second because it's discarded. Since an assignment returns its left side, only one element is available to @z from @a[0]. So, do we still have p5's 'want_array' (or whatever it was called)? That is, the predicate that tells the you whether the function is being called in item or list context? I know that the generalized 'want' function proved to be unworkable; but I'd expect p6 to at least be able to do everything that p5 can do; and that includes functions that are aware of whether they're being used as singular or plural. -- Jonathan Dataweaver Lang
Re: confusing list assignment tests
Thanks for the quick reply. Larry Wall wrote: On Tue, Jul 28, 2009 at 09:24:40PM +0200, Moritz Lenz wrote: : sub W () { substr(eval('want'), 0, 1) } : ... : : # line 560: : { : my @a; : my @z = (@a[0] = W, W); : #?rakudo 2 todo 'want function' : is(@a, 'L','lhs treats @a[0] as list'); : is(@z[0], 'L', 'lhs treats @a[0] as list'); : ok(!defined(@z[1]), 'lhs treats @a[0] as list'); : } : : : This tests that : 1) both calls to want() are in list context : 2) @a[0] gets only the return value of the first call to W() : 3) @z[0] gets the same thing : 4) There's no item for @z[1] : : Somehow I think this test (and many similar tests) are dead wrong. : Here's why: : : Either it's parsed as '@a[0] = (W, W)' (list assignment), then @a should : get both elements, and so should @z. Not according to S03, at least by one reading. @a[0] as a scalar container only wants one item, so it only takes the first item off the list, and the list assignment produces a warning on the second because it's discarded. Since an assignment returns its left side, only one element is available to @z from @a[0]. So it's parsed like a list assignment, but list-assigning to a scalar container doesn't promote the whole RHS to a Capture (or whatever it ends up being) as it would do in the case of item assignment, but takes one item off. OK. I guess when I initialize @a[0] = [] it's the same, because then @a[0] is still a scalar, right? Only when I wrote @a[0] := [] I'd get all items in @a[0]. : Or it's parsed as '(@a[0] = W), W' (item assignment), then the first : call should be in item context, and the second one in list context, and : @z should still get both items. It's not parsed like that, because only $x, $$xref, $($xref) and such are allowed targets for item assignment. Basically, it has to start with a $ sigil and not do anything fancy like subscripting. However, if you say @z = $x = $a, $b; it parses as @z = ($x = $a), $b and $b ends up in @z[1] but not in $x, which only gets $a. : Right? Or am I completely missing something important here? To get all the elements into $x you'd have to say @z = $x = ($a, $b); and @z[0] would be ($a,$b) with some type or other, whatever was returned by the parens, quite possibly Parcel (that is, List of Thunk or some such). Ok, that makes sense to me. : My current plan is to write such tests as : : sub l { 1, 2 } # return a short list : { : my @a; : my @z = (@a[0] = l(), l()); : is @a[0].elems, 4, '@a[0] = treats LHS as list' : is @z.elems,4, '... and passes all elements on the right'; : } : : Does this look sane, and match your understanding of assignment? Yes, but no. @z.elems and @a[0].elems should both be 1, I suspect. I wish we had a way of trapping and testing warnings too so we could see that 3 elements were discarded by the inner list assignment.. Larry Cheers, Moritz
Re: confusing list assignment tests
My understanding is that the P6 way to do that is to return a Capture containing the desired return values (which can lazily do things only when accessed) in the appropriate slots. On 7/28/09, Jon Lang datawea...@gmail.com wrote: Larry Wall wrote: Moritz Lenz wrote: : Either it's parsed as '@a[0] = (W, W)' (list assignment), then @a should : get both elements, and so should @z. Not according to S03, at least by one reading. �...@a[0] as a scalar container only wants one item, so it only takes the first item off the list, and the list assignment produces a warning on the second because it's discarded. Since an assignment returns its left side, only one element is available to @z from @a[0]. So, do we still have p5's 'want_array' (or whatever it was called)? That is, the predicate that tells the you whether the function is being called in item or list context? I know that the generalized 'want' function proved to be unworkable; but I'd expect p6 to at least be able to do everything that p5 can do; and that includes functions that are aware of whether they're being used as singular or plural. -- Jonathan Dataweaver Lang -- Sent from my mobile device Mark J. Reed markjr...@gmail.com
Re: confusing list assignment tests
Jon Lang wrote: Larry Wall wrote: Moritz Lenz wrote: : Either it's parsed as '@a[0] = (W, W)' (list assignment), then @a should : get both elements, and so should @z. Not according to S03, at least by one reading. @a[0] as a scalar container only wants one item, so it only takes the first item off the list, and the list assignment produces a warning on the second because it's discarded. Since an assignment returns its left side, only one element is available to @z from @a[0]. So, do we still have p5's 'want_array' (or whatever it was called)? No. That is, the predicate that tells the you whether the function is being called in item or list context? I know that the generalized 'want' function proved to be unworkable; but I'd expect p6 to at least be able to do everything that p5 can do; and that includes functions that are aware of whether they're being used as singular or plural. The problem is that it's impossible in Perl 6, because we have multi dispatch. Consider this simple case: multi a(@a*){ } # provides list context onto the arguments multi a(Str $x) { } # provides Str context or at least some sort of # item context on the argument sub b() { } a(b()); # you can't know which context b() is called in since the multi dispatch to a() depends on the return value of b(), we only know b()'s context after we know its return value - which is too late. So the active context propagation that Perl 5 does is not possible in Perl 6. Cheers, Moritz
Re: confusing list assignment tests
Mark J. Reed wrote: My understanding is that the P6 way to do that is to return a Capture containing the desired return values (which can lazily do things only when accessed) in the appropriate slots. Return a Capture or a more heavily overloaded object, depending on how fine a degree of context discrimination you need. Further to that idea, I'm actually planning to attempt to port Contextual::Return to Perl 6 in the next few weeks. Damian
Re: confusing list assignment tests
On Tue, Jul 28, 2009 at 01:22:28PM -0700, Jon Lang wrote: : Larry Wall wrote: : Moritz Lenz wrote: : : Either it's parsed as '@a[0] = (W, W)' (list assignment), then @a should : : get both elements, and so should @z. : : Not according to S03, at least by one reading. �...@a[0] as a scalar : container only wants one item, so it only takes the first item off : the list, and the list assignment produces a warning on the second : because it's discarded. Since an assignment returns its left side, : only one element is available to @z from @a[0]. : : So, do we still have p5's 'want_array' (or whatever it was called)? : That is, the predicate that tells the you whether the function is : being called in item or list context? I know that the generalized : 'want' function proved to be unworkable; but I'd expect p6 to at least : be able to do everything that p5 can do; and that includes functions : that are aware of whether they're being used as singular or plural. Perl 6 is not about doing everything that Perl 5 can do. It's about breaking everything that needs breaking. This is one of those things. We *may* have something like want someday, but if so, it can only work by time travel (read: return a type profile with lazy values, and let the eventual binding of the type profile call back for the actual values). But I doubt will require such for 6.0.0 in any case. But Perl 6 is based on knowing the types to do MMD, and we have to know at least those types, even if we don't know the values. That makes it very difficult for a function that wants to return *different* types based on the eventual dispatch, since the eventual dispatch depends on those types in a circular sort of way. Sanity dictates that we make time flow forward rather than backward for most of what Perl 6 programmers will want to do most of the time. Larry
Re: confusing list assignment tests
Damian Conway wrote: Mark J. Reed wrote: My understanding is that the P6 way to do that is to return a Capture containing the desired return values (which can lazily do things only when accessed) in the appropriate slots. Return a Capture or a more heavily overloaded object, depending on how fine a degree of context discrimination you need. Further to that idea, I'm actually planning to attempt to port Contextual::Return to Perl 6 in the next few weeks. Right. I don't think that a Capture has sufficiently fine context discrimination to handle even those cases that Perl 5 was able to handle. For instance, consider a function that's intended to return a list of items in list context, or a count of the items in item context: since imposing item context on a Capture object extracts the first positional parameter, a Capture object wouldn't be able to be loaded properly to do this. So something along the lines of Contextual::Return is probably a good idea. Hmm... it might be nice to be able to use something akin to a given ... when construct: sub foo() { return context { when Item { 5 } when List { a, b, c, d, e } } } The idea here is that the 'context' keyword means that the block is to be called as soon as the desired context is known, with said context being passed to the block as its topic ('$_'). -- Jonathan Dataweaver Lang
Re: confusing list assignment tests
On Tue, Jul 28, 2009 at 10:42:01PM +0200, Moritz Lenz wrote: : I guess when I initialize @a[0] = [] it's the same, because then @a[0] : is still a scalar, right? No, as in Perl 5 [] still produces a scalar object that hides the arrayness from list context, so it's like: $b = []; @a[0] = $b; It doesn't unwrap the scalar object to see what's in it. : Only when I wrote @a[0] := [] I'd get all items in @a[0]. That binds the Array in place of the current @a[0] container, just as $b = []; @a[0] := $b; would. Just as $obj and @$obj default differently in list context, so do [] and (). To put it another way, Array and Hash objects don't naturally interpolate into list context without some help from @ or % syntax (or equivalent method call). If I say: @a = 42, [1,2,3], { foo = 1, bar = 2, baz = 3 }; then @a will always end up with exactly 3 elements, just as if I'd said: $a = 42; $b = [1,2,3]; $c = { foo = 1, bar = 2, baz = 3 }; @a = $a, $b, $c; Larry