Click here to get back home

Readline using foreach and while

 HomeNewsGroups | Search | About
 comp.lang.perl.misc    Post an article   get this group's latest topics as an RSS feed add this group's latest topics to your My MSN content add this group's latest topics to your My Yahoo content
Subject Author Date
Readline using foreach and while Saurabh Jain 03-25-2008
Posted by szr on March 28, 2008, 11:00 am
Please log in for more thread options
Ben Morrow wrote:
>>
>> Actually the behaviors of "for (@ary)" and "for (@ary, ())" do seem
>> consistant if you really think about it. The resulting list is what
>> it iterates over (from the first element, to what ever *count* is...
>> in the former case *count* come fro mthe array, and since the
>> condition is checked at the start of each iteration, if the array is
>> added to, the count is incremented.
>>
>> In the latter case, a new list is created from contents of @ary + an
>> empty list, which gives you a new list, which contains the values of
>> @ary, but is a new seperate list, and thus is not effected by
>> changes to @ary because it has it's own copy of @ary's values.
>
> OK, now explain to me why
>
> my @ary = qw/a b c/;
> print map { /c/ and push @ary, 'd'; $_ } @ary;
>
> *doesn't* work like that :).
>
> Ben

For starters, we were talking about for(LIST), not map.


perldoc -f map

map BLOCK LIST
map EXPR,LIST
Evaluates the BLOCK or EXPR for each element of LIST
[...]


It would seem map does not re-check the count of the list each time
around like for those, which sort of makes sense, as it's supposed to
eval the block/expression for "each element", which to me means each
elemt of the list originally passed to map.

"map" and "for"/"foreach" are two similar but different beasts :)

--
szr



Posted by szr on March 28, 2008, 10:07 pm
Please log in for more thread options
Ben Morrow wrote:
>>
>> Actually the behaviors of "for (@ary)" and "for (@ary, ())" do seem
>> consistant if you really think about it. The resulting list is what
>> it iterates over (from the first element, to what ever *count* is...
>> in the former case *count* come fro mthe array, and since the
>> condition is checked at the start of each iteration, if the array is
>> added to, the count is incremented.
>>
>> In the latter case, a new list is created from contents of @ary + an
>> empty list, which gives you a new list, which contains the values of
>> @ary, but is a new seperate list, and thus is not effected by
>> changes to @ary because it has it's own copy of @ary's values.
>
> OK, now explain to me why
>
> my @ary = qw/a b c/;
> print map { /c/ and push @ary, 'd'; $_ } @ary;
>
> *doesn't* work like that :).

Actually it does. The difference is, map doesn't recheck the count every
time around like for/foreach do. If you print the contents of @ary after
the line with the map statement, it does indeed contain 'd' at the end.
This behavior seems to correct, as one would likely expect that the list
map returns when it is finished to be the same length as the one
/passed/ into map at the start. If you pass a 3 element list, you should
get back a 3 element list, should you not? Or do you consider this to be
a bug?

However, consider:

my @ary = qw/a b c/;
print map { /c/ and $_ = 'd'; $_ } @ary;


__OUTPUT__
abd

$_ is aliased to the current array element just like in for. Again, the
only difference I see if that map doesn't recheck the count of the
passed list for each iteration. Well, that and map returns a list :-)

To me, this behavior is part of what separates map from for/foreach.

--
szr



Posted by Ben Morrow on March 28, 2008, 10:48 pm
Please log in for more thread options

> Ben Morrow wrote:
> >>
> >> Actually the behaviors of "for (@ary)" and "for (@ary, ())" do seem
> >> consistant if you really think about it. The resulting list is what
> >> it iterates over (from the first element, to what ever *count* is...
> >> in the former case *count* come fro mthe array, and since the
> >> condition is checked at the start of each iteration, if the array is
> >> added to, the count is incremented.
> >>
> >> In the latter case, a new list is created from contents of @ary + an
> >> empty list, which gives you a new list, which contains the values of
> >> @ary, but is a new seperate list, and thus is not effected by
> >> changes to @ary because it has it's own copy of @ary's values.
> >
> > OK, now explain to me why
> >
> > my @ary = qw/a b c/;
> > print map { /c/ and push @ary, 'd'; $_ } @ary;
> >
> > *doesn't* work like that :).
>
> Actually it does. The difference is, map doesn't recheck the count every
> time around like for/foreach do. If you print the contents of @ary after
> the line with the map statement, it does indeed contain 'd' at the end.
> This behavior seems to correct, as one would likely expect that the list
> map returns when it is finished to be the same length as the one
> /passed/ into map at the start. If you pass a 3 element list, you should
> get back a 3 element list, should you not?

Absolutely not. my %h = map { $_ => 1 } qw/a b c/; is quite a common
idiom.

<snip>
> $_ is aliased to the current array element just like in for. Again, the
> only difference I see if that map doesn't recheck the count of the
> passed list for each iteration.

No, you're misunderstanding the difference between a list and an array.
Evaluating an array in list context returns a list of its elements *as
they are now*; under most circumstances, it returns a list of aliases to
those elements, but any changes to the order of the elements in @ary are
not propagated into the list. Consider

my @ary = qw/a b c/;
sub foo {
my @keep = map "$_", @_; # kill the aliasing
unshift @ary, 'h';
$_[$_] .= $keep[$_] for 0..$#_;
}
foo @ary;
print for @ary;

> To me, this behavior is part of what separates map from for/foreach.

It separates for (LIST) from everything else that accepts a LIST. This is
why I called it 'weird'.

Ben


Posted by szr on March 29, 2008, 11:47 am
Please log in for more thread options
Ben Morrow wrote:
>> Ben Morrow wrote:
>>>>
>>>> Actually the behaviors of "for (@ary)" and "for (@ary, ())" do seem
>>>> consistant if you really think about it. The resulting list is what
>>>> it iterates over (from the first element, to what ever *count*
>>>> is... in the former case *count* come fro mthe array, and since the
>>>> condition is checked at the start of each iteration, if the array
>>>> is added to, the count is incremented.
>>>>
>>>> In the latter case, a new list is created from contents of @ary +
>>>> an empty list, which gives you a new list, which contains the
>>>> values of @ary, but is a new seperate list, and thus is not
>>>> effected by changes to @ary because it has it's own copy of @ary's
>>>> values.
>>>
>>> OK, now explain to me why
>>>
>>> my @ary = qw/a b c/;
>>> print map { /c/ and push @ary, 'd'; $_ } @ary;
>>>
>>> *doesn't* work like that :).
>>
>> Actually it does. The difference is, map doesn't recheck the count
>> every time around like for/foreach do. If you print the contents of
>> @ary after the line with the map statement, it does indeed contain
>> 'd' at the end. This behavior seems to correct, as one would likely
>> expect that the list map returns when it is finished to be the same
>> length as the one /passed/ into map at the start. If you pass a 3
>> element list, you should get back a 3 element list, should you not?
>
> Absolutely not. my %h = map { $_ => 1 } qw/a b c/; is quite a common
> idiom.

Well, you're still getting that many *sets* which is probably what I
should of said, or have been clearer. In that example, you get 3 set of
hash pairs resulting from the 3 element list. The point is you get
count_of_passed_list amount of something from the map, in some form or
another. How exactly it's returned is determined by the template inside
the map.

> <snip>
>> $_ is aliased to the current array element just like in for. Again,
>> the only difference I see if that map doesn't recheck the count of
>> the passed list for each iteration.
>
> No, you're misunderstanding the difference between a list and an
> array. Evaluating an array in list context returns a list of its
> elements *as they are now*;

I seem to understand it just fine. What we both said above seems to be
true. Maybe we're just misunderstanding what the other is trying to say?
:-)

> under most circumstances, it returns a
> list of aliases to those elements, but any changes to the order of
> the elements in @ary are not propagated into the list. Consider
>
> my @ary = qw/a b c/;
> sub foo {
> my @keep = map "$_", @_; # kill the aliasing

Ok @keep now contains (a, b, c)...

> unshift @ary, 'h';

@ary, which comes from a scope outside this sub, now contains (h, a, b,
c)

> $_[$_] .= $keep[$_] for 0..$#_;

Keep in mind $_[0] *still* points to what used to be the first element
of @ary. Remember, the aliasing isn't to the *array* but to it's
*elements*. This is because when you normally pass args to a sub (e.g.,
do_something($x, $y); ), the aliasing is with $x and $y to $_[0] and
$_[1]. Passing an array just like passing that many scalars as are
elements in the array; each individual one gets aliased to the next
sequential element of @_ in the sub's scope.

> }
> foo @ary;
> print for @ary;

Running this (with the last line as `print "$_\n" for @ary;` for
clarity) prints:

h
aa
bb
cc

Seems the changes propgated just fine to me. You pushed 'h' to the
beginning of @ary, then you effectively iterated from
$ary[1]..$ary[$#ary].

Map is the same way in that regard; $_ is an alias to an *element*

>> To me, this behavior is part of what separates map from for/foreach.
>
> It separates for (LIST) from everything else that accepts a LIST.
> This is why I called it 'weird'.

I still don't see what you consider weird about it. What does it do that
you don't expect it to do?

--
szr



Posted by Uri Guttman on March 29, 2008, 12:02 pm
Please log in for more thread options

>> Absolutely not. my %h = map { $_ => 1 } qw/a b c/; is quite a common
>> idiom.

s> Well, you're still getting that many *sets* which is probably what I
s> should of said, or have been clearer. In that example, you get 3 set of
s> hash pairs resulting from the 3 element list. The point is you get
s> count_of_passed_list amount of something from the map, in some form or
s> another. How exactly it's returned is determined by the template inside
s> the map.

you are still missing the picture. map can return ANY number of elements
(not sets). it executes its expression/block once for each input element
but that can generate 0-?? elements which are appended to the return
list. there are no boundaries in those elements so there are no true
sets. if you return a reference which holds stuff you can force your own
boundaries and make sets. that is also a known map idiom. map generates
a new list from input from another list. the transformation can be
anything and isn't tied to how many input elements there are.

uri

--
Uri Guttman ------ uri@stemsystems.com -------- http://www.sysarch.com --
----- Perl Code Review , Architecture, Development, Training, Support ------
--------- Free Perl Training --- http://perlhunter.com/college.html ---------
--------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------

Similar ThreadsPosted
Asynchronous readline? September 6, 2004, 9:27 am
Term::ReadLine::GNU problem January 1, 2006, 11:57 am
ReadKey/ ReadLine query July 4, 2006, 2:40 am
readline - possible security hole March 30, 2007, 8:50 am
circular references, chdir() and Term::ReadLine::Gnu? February 7, 2006, 8:09 pm
Strange characters using Term::Readline on Win32 July 28, 2006, 9:05 am
HELP: readline() on unopened filehandle DATA at G:/PERLLIB/LIB/site_perl/5.8.2/MIME/WordDecoder.pm line 579. May 21, 2006, 10:59 am
foreach vs. for October 24, 2004, 6:18 pm
foreach in my May 18, 2005, 10:40 am
Using foreach?? maybe.. June 3, 2007, 12:30 pm

Our other projects:

Art Dolls, Fairies and Mermaids - Sunnyfaces.net

Roy's Linux, Programming and Search Engines messages

1-Script XML SitemapXML Sitemap