in reply to Changing array by changing $_?

JavaFan and others have already given a good explanation of what's going on, so I shalln't repeat them.

Instead I was going to advise that you can avoid the aliasing effect by using map and throwing away the output of the mapping, like this:

my @species =('HOMSAP','MUSMUS','-CIOINT'); map { /^-?(.+)$/; $_ = $1; unless (exists $refspecies{$_}) { # Species not in list die "$_ is not in the species table\n"; } } @species;
Grep could be used in the same way.

Fortunately, I tried this before posting. map fails in exactly the same way as foreach!

This means that some pretty innocuous code could be flawed. I think I might have used this form a few times in the past:

@in = qw{a b c -d -e}; @out = map { s/-//; $_ } @in;
I've been corrupting @in without realising!?! I should have been using this:
@in = qw{a b c -d -e}; map { s/-//; $_ } @out = @in;
Shame that looks so odd )-:

--
.sig : File not found.

Replies are listed 'Best First'.
Re^2: Changing array by changing $_?
by JavaFan (Canon) on Oct 13, 2008 at 13:56 UTC
    The reason map (and for/foreach and grep) make an alias instead of a copy is speed. A lot code, probably a majority of the code, doesn't modify $_ inside a map or grep; slightly less code will not modify $_ (or the loop variable) inside a for/foreach.

    If don't plan to modify $_, having an alias instead of a copy means the data doesn't have to be copied, saving memory and speed. This benefits everyone; the only case where extra code is needed is where one modifies $_ without the intention to modify the original array. That code has to do the copy explicitely.

    IMO, the right choice has been made.

      I would also like to add that this feature, in addition to speed, is a godsend in terms of saving (memory) space. Why make a copy of a variable when we only need to read it? Some other languages do make copies implicitly.

      When dealing with large datasets, the programmer needs to be aware of this behavior (of any programming language, for that matter) to ensure scalability.

      IMHO this is something that could usefully be rendered safer by strict, or similar. When it's useful to be able to modify $_ (or named alias) a little extra 'decoration' would not be material, and would highlight the use of this feature. The rest of the time it would reduce follicular wear and tear !

        I do not agree.

        If you need help in this department, write a Perl::Critic rule that checks whether you make a copy as the first line of your map/grep/for/foreach/sub block. Your suggestion would mean slowing down almost any scalar assignment done.

Re^2: Changing array by changing $_?
by ikegami (Patriarch) on Oct 13, 2008 at 14:05 UTC
    my @out = map { my $s = $_; $s =~ s/-//; $s } @in;
    my @out = @in; s/-// for @out;
    use List::MoreUtils qw( apply ); my @out = apply { s/-// } @in;
Re^2: Changing array by changing $_?
by TGI (Parson) on Oct 14, 2008 at 18:36 UTC

    I'd like to see a safe version of foreach, in analogous relationship with List::MoreUtils::apply and map.

    my @foo = 1..10; applyfor (@foo) { $_ *= 2; # Does not change @foo; print "$_\n"; } foreach ( @foo ) { $_ *= 2; # Changes @foo print "$_\n"; }

    applyfor() is a bad name, but I'm not sure what I'd call it. Maybe 'foreachcopy' would be good.


    TGI says moo