Re: confusing list assignment tests

2009-07-28 Thread Larry Wall
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

2009-07-28 Thread Jon Lang
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

2009-07-28 Thread Moritz Lenz
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

2009-07-28 Thread Mark J. Reed
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

2009-07-28 Thread Moritz Lenz
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

2009-07-28 Thread Damian Conway
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

2009-07-28 Thread Larry Wall
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

2009-07-28 Thread Jon Lang
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

2009-07-28 Thread Larry Wall
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