0

Below is the code snippet i have written, here the problem is $server variable cannot be passed inside the subroutines. How can i pass the value of a global variable inside a subroutine. Please help!

    use strict;
    use warnings;

    my (@list,$server);

    @list = qw/server1.net server2.net server3.net/;

    foreach $server(@list) {
    #calling sub-routines
    command1(); 
    command2();
    }

    sub command1 {
    print $server;
    system("command1");
    }

    sub command2 {
    print $server;
    system("command2");
    }
4
  • 4
    why use globals instead of passing the variable as argument ? Commented Jul 8, 2018 at 15:24
  • 3
    Crossposted to PerlMonks. Commented Jul 8, 2018 at 17:16
  • 2
    The obvious answer is to pass the $server variable into the subroutines (command1($server)). But you say "the problem is $server variable cannot be passed inside the subroutines". It would be interesting to here what is preventing you from doing that. Commented Jul 8, 2018 at 17:52
  • (1) It is very unreasonable that a variable can't be local and passed to a subroutine. You'd have to explain it really well why this is so (2) Given that, with foreach (@servers) { func() }; the $_ in the loop (another server in each iteration) is seen in the sub func as $_, so the sub is then sub func { $server = $_ ... }. But this is horrible and I hope you can just normally, explicitly and transparently, pass to the function what it needs. Commented Jul 8, 2018 at 22:50

2 Answers 2

1

One of the most important rules of good programming is to reduce coupling. Reducing a piece of code's dependencies on other pieces of code increases readability, increases maintainability, and decrease the chance of errors.

Your subs should not rely on having a global variable declared and available. The subs should have a server parameter instead.

For the same reason, you should also be limiting the scope of your variables to where they are needed.

use strict;
use warnings;
use feature qw( say );

sub command1 {
   my ($server) = @_;
   say $server;
   system("command1", $server);
}

sub command2 {
   my ($server) = @_;
   say $server;
   system("command2", $server);
}

{
   my @servers = qw( server1.net server2.net server3.net );

   for my $server (@servers) {
      command1($server); 
      command2($server);
   }
}
Sign up to request clarification or add additional context in comments.

Comments

-1

.. if you want to use globals:

our $server;
my (@list);

... rest of the code ...

or when you want to keep it a lexical, see also Perl foreach loop variable scope

use strict;
use warnings;


my (@list, $server);

@list = qw/server1.net server2.net server3.net/;

foreach (@list) {
  $server = $_;   # <<-- use it this way
  #calling sub-routines
  command1();
  command2();
}

sub command1 {
  print $server;
  system("command1");
}

sub command2 {
  print $server;
  system("command2");
}

preferred: pass as argument like:

use strict;
use warnings;

my (@list);

@list = qw/server1.net server2.net server3.net/;

foreach my $server(@list) {
  #calling sub-routines
  command1($server);
  command2($server);
}

sub command1 {
  my ($server) = @_;
  print $server, "\n";
  system("command1");
}

sub command2 {
  my ($server) = @_;
  print $server, "\n";
  system("command2");
}

4 Comments

Why do you insist on using a package variable for a global? Lexicals make perfectly good global variables.
update because of @Borodin's question. Bottom line is keep away from using globals. A trap is easily created. Using $server as a lexical here in the foreach does not do what you think it would
@ikegami: local ? : Can't localize lexical variable $server
Oh sorry, I thought you were using our. You're actually increasing the scope by using my instead of our+local.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.