2

If i give the variables as global it works fine. What is wrong with this code?

sub Multiply {
    $res = $a* $b;
    return ( $a, $b, $res);
}

main: 
my $a =3;
my $b =4;
my $res;
( $a, $b, $res) = Multiply();
print ("Input1 = $a\nInput2 = $b\nResult = $res");
keeru
  • 87
  • 6
  • @sborsky, It does it you presume `use strict; use warnings qw( all );`, which are often omitted on SO even if present in the script (as they should always be present). – ikegami Nov 06 '17 at 14:46
  • Thanks @ikegami, the title should have been hint enough, taking my former comment back. – sborsky Nov 07 '17 at 03:47

1 Answers1

5

The most important wrong thing is that you don't declare variables and don't have

use warnings;
use strict;

Also, using $a and $b is perilous since they are globals meant for sort.

The my variables $a, $b, $res are lexical but the ones in the sub are yet other, global variables; this is because the sub is defined before the lexicals are declared. They are never initialized, so their undefs overwrite lexicals on return. With use warnings; added

Use of uninitialized value $b in multiplication (*) at ..           [in sub]
Use of uninitialized value $a in multiplication (*) at ..           [in sub]
Use of uninitialized value $a in concatenation (.) or string at ..  [in print]
Use of uninitialized value $b in concatenation (.) or string at ..  [in print]

The global $res in the sub gets initialized to 0 and its return overwrites the lexical one.

If you were to put the code for the sub at the end it would "work," since lexicals get declared before the sub gets compiled so the sub sees them and uses them. But then again, if lexicals are in a "dynamic" scope that wouldn't work either; see this post. And altogether, using globals in a sub is not good.

Just declare variables in the subroutine and pass to it what it needs.

Then they exist only in the sub, also masking possible such names from outside scope. The sub has a well defined interface, returns values (scalars) which you assign as needed, and all is clear.

See Private Variables via my() in perlsub


Update

The title hints at use strict; being in place, and a comment states that. Then the question would be about declaration of variables.

The strict pragma requires, among a few other things, that all variables be declared or fully qualified.

The $res in the sub isn't declared, thus the compilation fails; the $a and $b exist as globals (but for use with sort – don't use them for convenience). A declared variable is seen in included scopes but with functions this isn't quite so simple and you want to declare all variables inside a function.

Global-like variables declared with our are OK but their use brings about other issues. While globals do get used occasionally they are very rarely needed and are best avoided, since their use can ruin clean scoping which is one of critical principles in programming.

A useful reference is perldiag, which explains error messages. Or, use diagnostics in debugging runs, or better yet use splain or run the code with perl -Mdiagnostics ...

zdim
  • 64,580
  • 5
  • 52
  • 81
  • i actually include strict and warnings. And i got error only with $res. That is because of $a and $b are exempt Global variable. use strict;use warnings; sub Multiply {my ($first, $second) = @_;my $res;$res = $first* $second;return ($res, ); } main: { my $first =3;my $second =4;my $res; ($res) = Multiply($first, $second); print ("Input1 = $first\nInput2 = $second\nResult = $res"); } The modified correct code! – keeru Nov 06 '17 at 07:36
  • @keeru Yes, that is the correct way to do it, as I state in the answer. But I don't understand "_i actually include strict and warnings. And i got error only with `$res`._" -- that is clear, the program doesn't compile because a variable is undeclared while `strict` is in effect. I thought you were asking about the output of the posted code? – zdim Nov 06 '17 at 07:38
  • @keeru Thinking about your comment some more, I added an "Update" – zdim Nov 06 '17 at 18:21