Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
what am I doing wrong here:
my @area = &circ_area(5,6,7); foreach (@area) { print $_ . "\n"; } sub circ_area { foreach (@_) { $_= 3.14 * ($_**2); } return (@_) }
Thanks,
Jonathan

Replies are listed 'Best First'.
Re: subroutine array question
by Sidhekin (Priest) on Aug 02, 2006 at 13:26 UTC
    what am I doing wrong here

    You are trying to modify 5, 6, and 7. It's a good thing Perl does not let you, or math would be a tricky thing to do.

    You might want to make some copies, somewhere or other. Since your function is returning values, you probably don't want it to also change the input values, and so I would choose to make the copies there:

    my @area = &circ_area(5,6,7); foreach (@area) { print $_ . "\n"; } sub circ_area { my @x = @_; # the copy is writable! foreach (@x) { $_= 3.14 * ($_**2); # so this works! } return (@x) }

    print "Just another Perl ${\(trickster and hacker)},"
    The Sidhekin proves Sidhe did it!

Re: subroutine array question
by davorg (Chancellor) on Aug 02, 2006 at 13:27 UTC

    You're trying to modify read-only values (as Perl has no doubt told you).

    Inside your subroutine, @_ contains three values (5, 6 and 7). But they aren't just values, they are the constants 5, 6 and seven. And in the foreach loop, $_ is aliases to each of those constants in turn. So when you try to assign a new value to $_, you are trying to overwrite the value of a constant. Which Perl, very sensibly, prevents you from doing.

    What you really want is something like this:

    sub circ_area { my @radii = @_; # copies values into a variable foreach (@radii) { $_= 3.14 * ($_**2); } return @radii; }

    Or, more Perlishly:

    sub circ_area { return map { 3.14 * ($_**2) } @_; }
    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: subroutine array question
by derby (Abbot) on Aug 02, 2006 at 13:23 UTC

    The error message tells you

    Modification of a read-only value attempted

    So re-write it:

    #!/bin/perl use strict; use warnings; my @vals = ( 5, 6, 7 ); my @area = &circ_area( @vals ); foreach (@area) { print $_ . "\n"; } sub circ_area { foreach (@_) { $_= 3.14 * ($_**2); } return (@_) }

    But since you're modifying the @_ var ... you really don't need to return it ... you're just needlessly copying the data.

    #!/bin/perl use strict; use warnings; my @vals = ( 5, 6, 7 ); &circ_area( @vals ); foreach (@vals) { print $_ . "\n"; } sub circ_area { foreach (@_) { $_= 3.14 * ($_**2); } }

    -derby
Re: subroutine array question
by Tanktalus (Canon) on Aug 02, 2006 at 13:27 UTC

    It'd be helpful if you showed any error messages or explained what you got vs what you expected to get.

    You seem to be using the parameters to circ_area as rvalues when you modify each parameter in turn. This will modify the original values as passed in, except that those values are constants and not modifyable. Then you return them - so that's just confusing. Why modify in place, and then return new copies?

    Also, you don't need the &. So get rid of it.

    Option 1:

    my @area = (5,6,7); circ_area(@area); # rest as-is
    Of course, this makes your code a liar - the area of those circles aren't 5, 6, and 7. The values are misleading until after the call to circ_area.

    Option 2:

    # rest as-is sub circ_area { map { 3.14 * ($_ ** 2) } @_; }
    Here we are creating a new array by mapping from the input values to some new output values. Since we don't assign back to $_, we aren't overwriting the constant inputs. This would be the way I suggest going.