sub should return modified value

B

Bart Van der Donck

Hello,

Suppose this code:

# ---------------------------
$a=2;
print "variable a has now value '$a'.\n";
&addone($a);
print "variable a has now value '$a'.\n";
sub addone
{
$b=shift;
$b++;
return $b;
}
# ---------------------------

gives as result:

variable a has now value '2'.
variable a has now value '2'.

Is it possible to have $a at value '3' after executing the sub ?
I tried with 'return', 'shift' and so, but couldn't find a way so that
$a would directly be affected by what happens in sub &addone (without
variable $a is mentionned in sub &addone obviously).

Thanks for tips or hints
Bart
 
A

Anno Siegel

Bart Van der Donck said:
Hello,

Suppose this code:

# ---------------------------
$a=2;
print "variable a has now value '$a'.\n";
&addone($a);
print "variable a has now value '$a'.\n";
sub addone
{
$b=shift;

$b is now a *copy* of the parameter
$b++;
return $b;
}
# ---------------------------

gives as result:

variable a has now value '2'.
variable a has now value '2'.

Is it possible to have $a at value '3' after executing the sub ?
I tried with 'return', 'shift' and so, but couldn't find a way so that
$a would directly be affected by what happens in sub &addone (without
variable $a is mentionned in sub &addone obviously).

You must modify the parameter in @_ directly.

sub addone { $_[ 0] ++ }

and even

sub addone { $_ ++ for shift }

do what you want. After assigning the value to a lexical in the
sub body, you increment *that* and not the original variable.

However, argument-modifying functions are problematic and should
normally be avoided. In languages like C, where a sub can only
return one value, there often is not much choice if more than one
result is needed from a sub. Perl subs can return as many values
as they want to, so there is rarely a need for argument-modification.

Anno
 
C

Chris Mattern

Bart said:
Hello,

Suppose this code:

# ---------------------------
$a=2;

Don't name variables $a; it has a special meaning to sort.
print "variable a has now value '$a'.\n";
&addone($a);

Don't use "&" in front of subroutine calls unless you know
what it does.
print "variable a has now value '$a'.\n";
sub addone
{
$b=shift;

Don't name variables $b; it has a special meaning to sort.
Don't use globals; limit the scope of subroutine variables:

my $variable=shift;

"use strict;" will help you enforce this practice (do "use
warnings;" too).
$b++;
return $b;
}
# ---------------------------

gives as result:

variable a has now value '2'.
variable a has now value '2'.

Well, why wouldn't it? You haven't done anything to change $a.
Is it possible to have $a at value '3' after executing the sub ?
Yes.

I tried with 'return', 'shift' and so, but couldn't find a way so that
$a would directly be affected by what happens in sub &addone (without
variable $a is mentionned in sub &addone obviously).

Thanks for tips or hints
Bart

"return" determines what value the subroutine returns--but you don't
use the return value in the code above; you throw it away. You need
something like this:

$a = addone($a);

--
Christopher Mattern

"Which one you figure tracked us?"
"The ugly one, sir."
"...Could you be more specific?"
 
T

Tad McClellan

Bart Van der Donck said:
$a=2;
print "variable a has now value '$a'.\n";
&addone($a);
print "variable a has now value '$a'.\n";
sub addone
{
$b=shift;
$b++;
return $b;
}

Thanks for tips or hints


Indent your code blocks so as to reveal your program's structure.

Use $a only for sort()ing, choose some other name for other purposes.

Don't use ampersands on function calls unless you know what it means
and what it means is what you want.

When you have a questions about subroutines, you should read the
standard docs for subroutines before asking thousands of people
around the world.

perldoc perlsub

Your question is answered in the 3rd paragraph...
 
B

Bart Van der Donck

First, thanks for you code. It works great!

I find it difficult to agree with your statement however:
However, argument-modifying functions are problematic and should
normally be avoided. In languages like C, where a sub can only
return one value, there often is not much choice if more than one
result is needed from a sub. Perl subs can return as many values
as they want to, so there is rarely a need for argument-modification.

In my experience, I have quite some need for this kind of approach.
I sometimes find myself in situations where I have a lot of variables
and they should all perform a same series of calculations.
E.g. when recalculating prices (discounts, adding % profit, currency
rates...), say:
&docalculations($priceppiece_1piece);
&docalculations($priceppiece_2pieces);
&docalculations($priceppiece_5pieces);
&docalculations($priceppiece_10pieces);
&docalculations($priceppiece_100pieces);
&docalculations($priceppiece_1piece_season);
&docalculations($priceppiece_2pieces_season);
&docalculations($priceppiece_5pieces_season);
&docalculations($priceppiece_10pieces_season);
&docalculations($priceppiece_100pieces_season);
etc.

In these cases, your sub would be perfect and the code gets far
clearer.
Why are argument-modifying functions problematic and to be avoided ?

Bart
 
J

Jim Cochrane

Hello,

Suppose this code:

# ---------------------------
$a=2;
print "variable a has now value '$a'.\n";
&addone($a);
print "variable a has now value '$a'.\n";
sub addone
{
$b=shift;
$b++;
return $b;
}
# ---------------------------

Pass a reference to the scalar to your subroutine instead of a copy:

#!/usr/bin/perl

use strict;
use warnings;

$a=2;
print "variable a is now '$a'.\n";
addone(\$a);
print "variable a is now '$a'.\n";

sub addone {
$b=shift;
$$b++;
return $b;
}
 
A

Anno Siegel

Bart Van der Donck said:
First, thanks for you code. It works great!

Whom are you thanking? Give some attribution and some context.
I find it difficult to agree with your statement however:


In my experience, I have quite some need for this kind of approach.
I sometimes find myself in situations where I have a lot of variables
and they should all perform a same series of calculations.
E.g. when recalculating prices (discounts, adding % profit, currency
rates...), say:
&docalculations($priceppiece_1piece);
&docalculations($priceppiece_2pieces);
&docalculations($priceppiece_5pieces);
&docalculations($priceppiece_10pieces);
&docalculations($priceppiece_100pieces);
&docalculations($priceppiece_1piece_season);
&docalculations($priceppiece_2pieces_season);
&docalculations($priceppiece_5pieces_season);
&docalculations($priceppiece_10pieces_season);
&docalculations($priceppiece_100pieces_season);
etc.

$priceppiece_1piece = docalculations($priceppiece_1piece);
...

would be clearer. Note missing "&" in front of the sub. I doubt that
it is needed here.

The explicit assignment is longer, but Perl has other means of saving typing.

$_ = docalculations( $_) for
$priceppiece_1piece,
$priceppiece_2pieces,
...
$priceppiece_100pieces_season;

is a first step, but really the related variables should be combined into
a hash:

my %priceppiece = (
1piece => <value>,
2_pieces => <value>,
...
100pieces_season => <value>,
);

Then the whole calculation becomes

$_ = docalculations( $_) for values %priceppiece.
In these cases, your sub would be perfect and the code gets far
clearer.

You mean shorter. An explicit assignment is always clearer than stealthily
changing a sub argument.
Why are argument-modifying functions problematic and to be avoided ?

Because the change is invisible to the sub user. You must *know* from
the documentation (is there documentation?) that a sub does that. With
explicit assignment, there can be no doubt.

It also restricts the applicability of a sub. "docalculations( 2.50)" is an
error with argument-modifying "docalculations". "$x = docalculations( 2.50)"
could be okay.

Anno
 
M

Michele Dondi

Suppose this code:

# ---------------------------

Don't! Two important lines missing:

use strict;
use warnings;

Nothing to do with your problem, but you'd better know anyway...

Don't! 'perldoc perlvar' && search '$a'.
print "variable a has now value '$a'.\n";
&addone($a);
^

Don't! Definitely obsolete && most probably not what you want.
print "variable a has now value '$a'.\n";
sub addone
{
$b=shift;
$b++;
return $b;
}
# ---------------------------

gives as result:

variable a has now value '2'.
variable a has now value '2'.

Correct!

You want

#!/usr/bin/perl -l

use strict;
use warnings;

my $u=2;
print 'variable $u has now value ', $u;
addone($u);
print 'variable $u has now value ', $u;

sub addone { $_[0]++ }

__END__

instead!


Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,147
Messages
2,570,835
Members
47,383
Latest member
EzraGiffor

Latest Threads

Top