Very serios perl problem? (BUG?)

M

Mihail

Hello,

i have spent several hours with very small perl
program and i believe there is something wrong with
perl. Look:

for (1..999)
{
my $i = $_;
$result1 = $result1 + func1($i);
$result2 = $result2 + func2($i);
}

This code contains absolute critical error, but it is
visible only with "use warnings", otherwise perl returns
silently wrong results. To achieve correct results i have
to use:

for (1..999)
{
my $i = $_;
$result1 = $result1 + func1($i);
$i = $_;
$result2 = $result2 + func2($i);
}

O.K. i know unsafety of "$_". But what is wrong with $i? More
interesting. The problem seems to depend on functions used.

I am really confused... Can anybody explain what is wrong.

Regards,
Mihail

----------------------------------------------------------------

#!/usr/bin/perl
use strict;
use warnings;

my $result1 = 0;
my $result2 = 0;

for (1..999)
{
my $i = $_;
$result1 = $result1 + func1($i);
# HERE IS A PROBLEM. $i is undef??????
# and RESULT IS WRONG!!!

#$i = $_; # is a workaround.
$result2 = $result2 + func2($i);
}
print "*** Sum of first sums of digits : $result1\n";
print "*** Sum of last sums of digits : $result2\n";


# TRY TO RENAME func1 <-> func2 below - PROGRAMM BEHAVIOR WILL
# CHANGE. ????????

sub func1
{
my $sum = 0;
do
{
$_[0] =~ m/^(.).?/;
$sum = $sum + $1;
$_[0] =~ s/^.//;
} while ($_[0]);
return $sum;
}

sub func2
{
return $_[0] % 9 if (($_[0] % 9) > 0);
return 9;
}
------------------------------------------------------------
 
E

Eric Bohlman

i have spent several hours with very small perl
program and i believe there is something wrong with
perl. Look:

No there isn't. You've discovered a feature, not a bug.
#!/usr/bin/perl
use strict;
use warnings;

Thank you for doing this.
my $result1 = 0;
my $result2 = 0;

for (1..999)
{
my $i = $_;
$result1 = $result1 + func1($i);
# HERE IS A PROBLEM. $i is undef??????
# and RESULT IS WRONG!!!

That's because func1() is capable of altering its argument, and did so.
#$i = $_; # is a workaround.
$result2 = $result2 + func2($i);
}
print "*** Sum of first sums of digits : $result1\n";
print "*** Sum of last sums of digits : $result2\n";


# TRY TO RENAME func1 <-> func2 below - PROGRAMM BEHAVIOR WILL
# CHANGE. ????????

sub func1
{
my $sum = 0;
do
{
$_[0] =~ m/^(.).?/;
$sum = $sum + $1;
$_[0] =~ s/^.//;

You've altered $_[0]. When you call a sub with arguments, the elements
of @_ become *aliases* to the arguments themselves. When you call this
from your main program, $_[0] has become an alias to $i, and the
preceding statement has exactly the same effect as:

$i =~ s/^.//;

so $i eventually winds up empty.
} while ($_[0]);
return $sum;
}

sub func2
{
return $_[0] % 9 if (($_[0] % 9) > 0);
return 9;
}

Here you never alter $_[0] and therefore never alter $i.
 
T

Tad McClellan

Mihail said:
i have spent several hours with very small perl
program and i believe there is something wrong with
perl.


No, there is something wrong with your understanding of Perl.

It is doing exactly what you told it to do.

O.K. i know unsafety of "$_". But what is wrong with $i? More
interesting. The problem seems to depend on functions used.

I am really confused... Can anybody explain what is wrong.


The third paragraph of

perldoc perlsub

can explain what is wrong.

for (1..999)
{
my $i = $_;
$result1 = $result1 + func1($i);
# HERE IS A PROBLEM. $i is undef??????
# and RESULT IS WRONG!!!

#$i = $_; # is a workaround.

# TRY TO RENAME func1 <-> func2 below - PROGRAMM BEHAVIOR WILL
# CHANGE. ????????

sub func1
{
$_[0] =~ s/^.//;


The array C<@_> is a local array, but its
elements are aliases for the actual scalar parameters. In particular,
if an element C<$_[0]> is updated, the corresponding argument is
updated

You are changing the alias, so the change is reflected back
in the _caller's_ variable ($i).

Change a copy instead:

sub func1
{ my($arg) = @_;
...
$arg =~ s/^.//;
 
M

Mihail

Many thanks for replies.
It is doing exactly what you told it to do.

No. But I know now why (thanks), but still don't like it. I have passed
an argument to function to get results calculated from it. But why perl
must change the variable passed as argument globally? Why it does not
simply use the value of this variable. May be it can be usefull in some
cases, but is it not dangerous?
 
J

Jürgen Exner

Mihail said:
Many thanks for replies.


No.

Yes, it does. Although it may not do what you intended it to do.
But I know now why (thanks), but still don't like it. I have
passed an argument to function to get results calculated from it. But
why perl must change the variable passed as argument globally? Why it
does not simply use the value of this variable. May be it can be
usefull in some cases, but is it not dangerous?

You may want to read up about parameter passing methods in programming
languages, in particular call by value versus call by reference.

To make a long story short: most programmer find call by value to be too
limiting:
- any value that is computed by the sub must be passed back as the return
value of this sub. This can become very awkward if the sub returns multiple
values.
- a sub cannot just change a specific entry in a complex data structure but
instead it must return a new complex data structure which in turn must be
'saved' in the calling sub
- ...

jue
 
M

Mihail

You may want to read up about parameter passing methods in programming
languages, in particular call by value versus call by reference.

Syntaxis i used is "pass by value" and i passed the value, but it works
like pass by reference in C++.
 
M

Mihail

program and i believe there is something wrong with perl.
No, there is something wrong with your understanding of Perl.

And what about Larry Wall? I hope you have no problem with his
understanding. :) BTW. I have no doubt perl is great language.

http://www.perl.com/pub/a/2003/03/07/apocalypse6.html



That is, Perl 6 will supply a default parameter signature (the precise
meaning of which will be explained below) that makes the subroutine
behave much as a Perl 5 programmer would expect, with all the arguments
in @_. It is not exactly the same, however. You may not modify the
arguments via @_ without declaring explicitly that you want to do so. So
in the rare cases that you want to do that, you'll have to supply the rw
trait (meaning the arguments should be considered "read-write"):


sub swap (*@_ is rw) { @_[0,1] = @_[1,0] };
 
P

Paul Lalli

No, you did not use pass by value. There is no way to specify pass by
value. It is your conception of what pass by value vs pass by
reference "should" look like that is flawed. Remove your
preconceptions about how you think the language should work, and there
is no issue.
Perl does not have consistent syntaxis for it.

I have no idea what you mean by this. It's very consistent. Every
single subroutine argument is passed into @_, whether it was originally
a scalar variable, a string or numeric litteral, or a member of a list
or array.
Scalars are only "passed
by reference" with syntaxis which does not look like so.

What do you mean by "look like"? It "looks" just fine to me. If it's
an argument, it's in @_. If I modify an element of @_, I've modified
the argument.
But arrays are even more difficult (just read).

I have no idea what that means.

Paul Lalli

P.S. I realize English is not your first language, so please take this
as the assistance in which it is intended: The word is "syntax", not
"syntaxis". It would be highly unusual to use a plural form of the
word, but if one did, I believe it would be "syntaxes".
 
J

Jürgen Exner

Dr.Ruud said:
Paul Lalli:


I have code with ('' . $value) and (0 + $value).

Sorry, I must be missing the point.
What do those two code snippets have to do with pass by value versus pass by
reference?

jue
 
T

Tad McClellan

But nearly everyone gets the _effect of_ pass by value because
their subroutines copy the args and then operate only on the copies.

Sorry, I must be missing the point.
What do those two code snippets have to do with pass by value versus pass by
reference?


It makes the alias be a non-lvalue and therefore unchangeable,
as in pass by value.


-----------------------------
#!/usr/bin/perl
use warnings;
use strict;

my $value = 5;
change_alias($value);
print "$value\n";

$value = 5;
change_alias(0 + $value);
print "$value\n";

sub change_alias { $_[0] = 'changed' }
 
D

Dr.Ruud

Jürgen Exner:
Dr.Ruud:

Sorry, I must be missing the point.
What do those two code snippets have to do with pass by value versus
pass by reference?

I looks to me like someone prevented that a sub would (now or ever)
change a parameter.

Example:

#!/usr/bin/perl
use strict;
use warnings;

{ local ($,, $\) = (":\t", "\n");

my $x = 'test';

print '-';

print 'before', $x;
munge('' . $x);
print 'after', $x;
print '-';

print 'before', $x;
munge($x);
print 'after', $x;
print '-';
}

sub munge {
$_[0] = 'xxx';
}
 
R

Robert Sedlacek

Mihail said:
And what about Larry Wall? I hope you have no problem with his
understanding. :) BTW. I have no doubt perl is great language.

Perl 5 != Perl 6. The reasons Perl 6 does things in other ways than Perl
5 are no excuse for not reading the documentation. Letting this aside,
you should be more cautious with your wording. Stating what a Perl
developer would expect and stating that there is a bug in perl *without*
having read the documentation won't bring you many friends in here.
 
M

Mihail

But arrays are even more difficult (just read).
I have no idea what that means.

I mean this (from perldoc perlsub). No idea, no example.

"Because the assignment copies the values, this also has the effect of
turning call-by-reference into call-by-value. Otherwise a function is
free to do in-place modifications of @_ and change its caller's values."
 
M

Mihail

"Because the assignment copies the values, this also has the effect of
turning call-by-reference into call-by-value. Otherwise a function is
free to do in-place modifications of @_ and change its caller's values."

Sorry, it is a workaround described in thread before. It is clear.

There is another issue not completely clear for me (below), what "whole
array @_" removes .. I'll try to test it.

If an argument is an array or hash element which did not exist when the
function was called, that element is created only when (and if) it is
modified
or a reference to it is taken. (Some earlier versions of Perl created
the element whether or not the element was assigned to.) Assigning to the
whole array @_ removes that aliasing, and does not update any arguments.


Thank you very much for answers and do not be too angry. I did not post
a bug and used "?" in my Subj. Perl6 seems to be the same opinion -
default will be "call-by-value".
 

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
473,769
Messages
2,569,582
Members
45,068
Latest member
MakersCBDIngredients

Latest Threads

Top