Iterator semantics

2008-09-09 Thread Patrick R. Michaud
I think my question can be best understood by example -- what
does the following produce?

my @a = 1,2,3,4,5;
for @a { .say; @a = (); }

My question is whether the change to @a inside the for loop
affects the iterator created at the beginning of the for loop.
In other words, would the above produce 1\n2\n3\n4\n5\n  or
1\n ?

My followup question is then:

my @a = 1,2,3,4,5;
my @b = 6,7,8;

for @a,@b { .say; @b = (); }

I have more examples involving various aspects of list and
iterator semantics, but the answers to the above will help guide
my questions.

Pm


Re: adverbial form of Pairs notation question

2008-09-09 Thread TSa

HaloO,

Jon Lang wrote:

Actually, note that both infix:, and circumfix:[ ] can be used to
build lists; so [1] and [] can be used to construct single-element and
empty lists, respectively.


I doubt that. Actually, circumfix:[ ] builds arrays. And note that
there's no infix operator that concatenates arrays. '[1,2],[3,4]' is
a two element list. The closest you can get is '[1,2].push: [3,4]'
which preserves the identity of the first array whereas the lists
in infix, behave like values. I.e. the concatenated list has got
a new identity, not that of the left list.



Personally, I'd like to see '()' capture the concept of nothing in
the same way that '*' captures the concept of whatever.  There _may_
even be justification for differentiating between this and something
that is undefined (which 'undef' covers).  Or not; I'm not sure of
the intricacies of this.  One possibility might be that '1, 2, undef'
results in a three-item list '[1, 2, undef]', whereas '1, 2, ()'
results in a two-item list '[1, 2]' - but that may be a can of worms
that we don't want to open.


I see no can of worms. A *defined* () as nothing is just as well
defined as 0 is for addition of numbers or '' for string concatenation.
The thing that Larry's line of thought leads to is that

   my $a = () // (1,2);

means that $x receives (1,2) not the nothing object. The question
that arises when comparing () to * is how polymorph () is:

   my $b =3 + ();# $b == 3?
   my $c = 'ab' ~ ();# $c eq 'ab'?
   my $d =  1,2 , ();# $d === (1,2)
   my $e =3 * ();# $e == 0?
   my $f =   3 ** ();# $f == 1?
   my $g = () ?? 1 !! 2; # $g == 2?
   my $h;# $h === ()? scalar defaults to nothing

Do the Nothing and Whatever have unique IDs?

   my %h;
   %h{()} = Nothing;
   %h{*} = Whatever;
   %h{*+3} = Whatever plus three;

I guess for hashes there is no slicing implied by the latter two cases,
so these would use the .WHICH to build the index.


Regards, TSa.
--

The unavoidable price of reliability is simplicity -- C.A.R. Hoare
Simplicity does not precede complexity, but follows it. -- A.J. Perlis
1 + 2 + 3 + 4 + ... = -1/12  -- Srinivasa Ramanujan


Re: Iterator semantics

2008-09-09 Thread Larry Wall
On Tue, Sep 09, 2008 at 10:10:04AM -0500, Patrick R. Michaud wrote:
: I think my question can be best understood by example -- what
: does the following produce?
: 
: my @a = 1,2,3,4,5;
: for @a { .say; @a = (); }
: 
: My question is whether the change to @a inside the for loop
: affects the iterator created at the beginning of the for loop.
: In other words, would the above produce 1\n2\n3\n4\n5\n  or
: 1\n ?
: 
: My followup question is then:
: 
: my @a = 1,2,3,4,5;
: my @b = 6,7,8;
: 
: for @a,@b { .say; @b = (); }
: 
: I have more examples involving various aspects of list and
: iterator semantics, but the answers to the above will help guide
: my questions.

At the moment the design of Perl 6 (unlike certain FP languages) is
that any dependence on the *degree* of laziness is erroneous, except
insofar as infinite lists must have *some* degree of laziness in order
not to use up all your memory immediately.  But any finite list can
do any amount of batching it pleases, so there's no foolproof way to
tell a lazy finite list from an eager list.  Modifying the inputs to
a lazy list is basically asking for undefined behavior.

This seems to me like the most multicore-friendly default, though
perhaps not the most programmer friendly.  It seems to me that any
programming involving cyclic lazy feeds must somehow have an eager
in it somewhere to prevent indeterminacy, but I don't know how to
write a compiler that enforces that offhand.

Larry


Re: Iterator semantics

2008-09-09 Thread TSa

HaloO,

Patrick R. Michaud wrote:

My question is whether the change to @a inside the for loop
affects the iterator created at the beginning of the for loop.


Since Larry said that single assignment semantics is the ideal
we should strive for, I would opt for the iterator being unaffected
by the assignment to @a. When this happens the singly assigned
former content of @a is snaphot by the iterator. This also preserves
the former lazyness state. If possible the optimizer factors
out the assignments after the loop.


Regards, TSa.
--

The unavoidable price of reliability is simplicity -- C.A.R. Hoare
Simplicity does not precede complexity, but follows it. -- A.J. Perlis
1 + 2 + 3 + 4 + ... = -1/12  -- Srinivasa Ramanujan


Re: Iterator semantics

2008-09-09 Thread John M. Dlugosz

My take on it:

The 'for' loop does bind $_ to alias each item of the list in turn.  
But, the list is not synonymous with the variable named @a.  However, 
the = operator operates on the list itself, not the container, 
replacing the elements in the existing Array (or whatever) object.  So, 
the first iteration through the loop would indeed replace all the 
elements in the object being iterated over.


The semantics of the 'for' loop are sequential.  It is a 
programming-flow construct, not a data-manipulation construct.  So 
laziness within the list is not an issue.  If some elements are 
delayed-evaluation, they get overwritten so that evaluation is never done.


The follow-up question is more interesting.  The operation of @a,@b 
makes a new List object.  Just like =after= calling $c=$a+$b it does not 
matter if you change $a.  Imagine + being lazy with thousand-digit 
numbers so it might avoid actually doing it 'till you needed (if ever) 
the answer.  It would be unacceptable if it appeared to bind to the 
original arguments indefinitely.
If the comma concatenation is lazy it needs to be on a deeper level so 
it does not seem to depend on the arguments not changing afterwards.  It 
might, in particular, copy all the primitive components out of @b which 
includes range objects and other lazy lists, or arrange a copy-on-write 
sharing with @b.  I've done this kind of stuff with my C++ classes, so 
I'm familiar with the scenario.  That is, give the outward appearance of 
value semantics but share storage or defer work internally.  @a,@b 
produces a well-defined value.


So, the first example prints 1 only, and the second prints 1 through 8.

--John

Patrick R. Michaud pmichaud-at-pobox.com |Perl 6| wrote:

I think my question can be best understood by example -- what
does the following produce?

my @a = 1,2,3,4,5;
for @a { .say; @a = (); }

My question is whether the change to @a inside the for loop
affects the iterator created at the beginning of the for loop.
In other words, would the above produce 1\n2\n3\n4\n5\n  or
1\n ?

My followup question is then:

my @a = 1,2,3,4,5;
my @b = 6,7,8;

for @a,@b { .say; @b = (); }

I have more examples involving various aspects of list and
iterator semantics, but the answers to the above will help guide
my questions.

Pm

  




Re: Iterator semantics

2008-09-09 Thread John M. Dlugosz

TSa Thomas.Sandlass-at-vts-systems.de |Perl 6| wrote:

Since Larry said that single assignment semantics is the ideal
we should strive for, I would opt for the iterator being unaffected
by the assignment to @a. When this happens the singly assigned
former content of @a is snaphot by the iterator. 


That's what my C++ vararray class does with iterators.  That way they 
don't go stale if you manipulate the array during iteration.


Iterators are independent objects in Perl 6 that can be used in other 
ways.  I think it vaguly specifies in the synopses that the for loop 
will use the default iterator for that List, provided by a member for 
that purpose.


You can have different iterator types that work in different ways.  You 
can create which ever kind you need for the purpose.


The synopses does not specify the details of iterators.  But you can 
logically deduce that the default iterator needs to provide for rw (not 
ref?) binding, since the for loop is documented to do that, if the for 
loop uses the default iterator.  The meta-law is that things work like 
in Perl 5 unless specified otherwise, so the for loop needs to continue 
to track the changing contents of the List object. 



But I imagine you can create an iterator with various options: snapshot 
or tracking, rw, readonly, or ref, and other attributes.


So if you really wanted to depend on those semantics, you could write 
something like


   my $it = @a.iterator(:snapshot);
   while =$it - { body-of-loop }

You could allow adverbs on the 'for' loop to pass through to the call to 
iterator(), but that is probably too much syntactic sugar for the value 
it gives.


--John


Re: Iterator semantics

2008-09-09 Thread Daniel Ruoso
Ter, 2008-09-09 às 10:10 -0500, Patrick R. Michaud escreveu:
 I think my question can be best understood by example -- what
 does the following produce?
 my @a = 1,2,3,4,5;
 for @a { .say; @a = (); }

The problem actually becomes more evident with

  my @a = 1,2,3,4,5;
  for @a { .say; @a[5] = 'five' }

because the first code actually replaces the content of the variable @a,
while the second will call .postcircumfix(5), which itself returns a
container which is then STOREd with 'five'.

The basic difference is that in 

  for @a {...}

we take an iterator that point to the array that is stored at that
moment in @a. If we replace the array stored in the variable @a, that
iterator would still point to the original array.

The second example actually modifies the object stored in the variable
'@a'. And that is a different issue.

daniel