Conditionally including a module in perl - perl

I am new to perl, just encountered one case.
Can someone tell why does this fail with error
Undefined subroutine &main::color
$condition = 1;
use if ( $condition ), Term::ANSIColor;
print color('bold red');
print "hii";
print color('reset');
and this passes
use if ( 1 ), Term::ANSIColor;
print color('bold red');
print "hii";
print color('reset');

This is because use statements are executed at compile time, while your assignment is performed at run time and hasn't been executed yet
You can fix this by using a BEGIN block to do the assigmment at compile time as well, like this. Note that the variable must be declared outside the block, otherwise it will be local to the block and will disappear before it is neded
my $condition;
BEGIN {
$condition = 1;
}
use if $condition, 'Term::ANSIColor';
print color('bold red');
print "hii";
print color('reset');
Note also that you should always have use strict and use warnings 'all' at the top of every Perl program. If you had these in place you would need to quote the module name, as shown above

Related

How to convince Devel::Trace to print the BEGIN-block statements?

Have a simple script p.pl:
use strict;
use warnings;
our $x;
BEGIN {
$x = 42;
}
print "$x\n";
When I run it as:
perl -d:Trace p.pl
prints:
>> p.pl:3: our $x;
>> p.pl:7: print "$x\n";
42
how to get printed the BEGIN block statements too, e.g. the $x = 42;?
Because my intention isn't clear, adding the clarification:
Looking for ANY way to print statements when the perl script runs (like Devel::Trace it does) but including the statements in the BEGIN block.
It's very possible. Set $DB::single in an early BEGIN block.
use strict;
use warnings;
our $x;
BEGIN { $DB::single = 1 }
BEGIN {
$x = 42;
}
print "$x\n";
$DB::single is a debugger variable used to determine whether the DB::DB function will be invoked at each line. In compilation phase it is usually false but you can set it in compilation phase in a BEGIN block.
This trick is also helpful to set a breakpoint inside a BEGIN block when you want to debug compile-time code in the standard debugger.
Disclaimer: This is just an attempt to explain the behaviour.
Devel::Trace hooks up to the Perl debugging API through the DB model. That is just code. It installs a sub DB::DB.
The big question is, when is that executed. According to perlmod, there are five block types that are executed at specific points during execution. One of them is BEGIN, which is the first.
Consider this program.
use strict;
use warnings;
our ($x, $y);
BEGIN { $x = '42' }
UNITCHECK { 'unitcheck' }
CHECK { 'check' }
INIT { 'init' }
END { 'end' }
print "$x\n";
This will output the following:
>> trace.pl:8: INIT { 'init' }
>> trace.pl:3: our ($x, $y);
>> trace.pl:11: print "$x\n";
42
>> trace.pl:9: END { 'end' }
So Devel::Trace sees the INIT block and the END block. But why the INIT block?
Above mentioned perlmod says:
INIT blocks are run just before the Perl runtime begins execution, in "first in, first out" (FIFO) order.
Apparently at that phase, the DB::DB has already been installed. I could not find any documentation that says when a sub definition is run exactly. However, it seems it's after BEGIN and before INIT. Hence, it does not see whatever goes on in the BEGIN.
Adding a BEGIN { $Devel::Trace::TRACE = 1 } to the beginning of the file also does not help.
I rummaged around in documentation for perldebug and the likes, but could not find an explanation of this behaviour. My guess is that the debugger interface doesn't know about BEGIN at all. They are executed very early after all (consider e.g. perl -c -E 'BEGIN{ say "foo" } say "bar"' will print foo.)

Perl syntax error printing list index

I am trying to print an index of a list returned from a function call. I am wrapping the function call in parenthesis in an attempt to convert the list to an array. The program fails to compile saying 'syntax error at file.pl line 4, near ")["'. If I create a temporary variable $a or use printf indexing is fine. Why does print brake, is there a better alternative?
sub get{
return (1,2);
}
#print (get())[0]; #fails
printf("%d",(get())[0]);
my $a = (get())[0];
print $a;
I assume that you are foolishly not using
use warnings;
Which is quite a bad thing to not do. If you had used it, you would get the warning:
print (...) interpreted as function
Which is to say, what you wrote
print (get())[0]
Is something Perl interprets as you trying to put a subscript on the print() function. This does not work.
For the code to do what you expect, you need to be explicit about the parentheses:
print ( (get())[0] );
You should always use
use strict;
use warnings;
There is a slight learning curve to using these, but they only show you your errors. Not using them only hides your errors, and your code does not work better.
Try this :
sub get{
return (1,2);
}
print((get)[0]);
or
my $a = (get)[0];
print $a;
OUTPUT
1

Dependency between perl modules

Suppose I have three perl modules as given below :
Test.pm
package Test;
use strict;
use warnings;
use Check;
our $data = Check->getX;
1;
Initialize.pm
package Initialize;
use Check;
use Test;
Check->setX(10);
our $t = $Test::data;
print $t;
1;
Check.pm
package Check;
my $x = 12;
sub setX {
my ($self,$value) = #_;
$x = $value;
}
sub getX
{
return $x;
}
1;
Now, when I run Initialize.pm, I am initializing $x in Check.pm to 10 and $x is assigned to $data in Test.pm. But the the actual valuethat is assigned to $data is 12 which is the initial value given in Check.pm.
So, When are the global variables initialized in perl? How can I enforce that the new value set by me in the Initialize.pm to x is what is loaded into $data?
Now if I replace the statement use Test in Initalize.pm with require Test; and move the statement Check->setX(10) before this require statement then $data is correctly initialized to the new value 10. What is it that is happening differently in this case ?
In general modules have little or no executable code. Object-oriented modules just define the object methods, and sometimes some class data.
When you use Test the whole of Test.pm is compiled and executed, so the value of $data is set at this point.
The call to setX happens straight afterwards, but is too late to affect the asignment of $data.
As I said in my comment your code has a very odd structure, and modules shouldn't have a time dependency on each other at all. You should really remove all executable statements from your modules, but to force your code to do what you want you can write
use strict;
use warnings;
use Check;
BEGIN {
Check->setX(10);
}
use Test;
our $t = $Test::data;
print $t;
But don't do that!
Perl executes a use statement prior to executing anything else in the file.
So the execution order is:
use Check;
$x = 12;
use Test;
use Check; -This only does importing as the file is already executed
$data = Check->getX();
Check->setX(10);
If you replace use with require the instruction is evaluated at the same time as the rest of the instructions and if you move Check->setX(10); before the require it will be evaluated before the get in Test

Prevent Perl from printing identical warning messages

Consider the following nonsense script as an example:
use strict;
use warnings;
my $uninitialisedValue;
while(<>){
print ${$uninitialisedValue}{$_},"\n";
}
Which is run from the command line:
$ perl warningPrinter.pl < longfile.txt
Regardless of what standard input contains, standard output will be full of:
Use of uninitialized value in print at warningPrinter.pl line 16, <> line 1.
Use of uninitialized value in print at warningPrinter.pl line 16, <> line 2.
Use of uninitialized value in print at warningPrinter.pl line 16, <> line 3.
Use of uninitialized value in print at warningPrinter.pl line 16, <> line 4.
...
I work with very long files, so receiving this as output when testing my script is at the very least mildly irritating. It can take a while for the process to respond to a Ctrl + C termination signal and my terminal is suddenly filled with the same error message.
Is there a way of either getting Perl to print just the first instance of an identical and reoccurring warning message, or to just make warning messages fatal to the execution of the script? Seeing as I have never produced a script that works despite having warnings in them, I would accept either. But it's probably more convenient if I can get Perl to print identical warnings just once.
I thought I would show you how unique warning logic might be created. I don't recommend it though:
my %printed;
local $SIG{__WARN__} = sub {
my $message = shift;
my ( $msg, $loc ) = $message =~ m/(.*?) at (.*?line \d+)/;
print $message unless $printed{$loc}{$msg}++;
};
I should say that I do not recommend this as a general practice. Because it's better to have a warning policy. It's either an operation that can take an undefined value, or you don't want to handle an undef value. I try to remove all warnings from my completed code.
In the first case, putting no warnings 'uninitialized'; in the for loop is a much easier--and regular thing to do. In the second case, you'd probably want to fail.
However, if it is something you would actually like to handle but warn once about, say that you wanted robust handling of the data, but wanted to warn upstream processes that you got some bad data, you could go about creating a sub warn_once:
{ use Carp ();
my %warned;
sub warn_once {
my $message = shift;
my ( $msg, $loc ) = $message =~ m/(.*?) at (.*?line \d+)/;
Carp::carp( $message ) unless $warned{$loc}{$msg}++;
};
}
And call it like this:
while ( <> ) {
warn_once( '$uninitialisedValue is uninitialized' )
unless defined( $uninitialisedValue)
;
no warnings 'uninitialized';
print ${$uninitialisedValue}{$_},"\n";
}
Then you have decided something.

break out of a subroutine

what is the best way to break out of a subroutine & continue processing the rest of the script?
ie
#!/usr/bin/perl
use strict;
use warnings;
&mySub;
print "we executed the sub partway through & continued w/ the rest
of the script...yipee!\n";
sub mySub{
print "entered sub\n";
#### Options
#exit; # will kill the script...we don't want to use exit
#next; # perldoc says not to use this to breakout of a sub
#last; # perldoc says not to use this to breakout of a sub
#any other options????
print "we should NOT see this\n";
}
At the expense of stating the obvious the best way of returning for a subroutine is ......
return
Unless there is some hidden subtlety in the question that isn't made clear
Edit - maybe I see what you are getting at
If you write a loop, then a valid way of getting out of the loop is to use last
use strict ;
use warnings ;
while (<>) {
last if /getout/ ;
do_something() ;
}
If you refactor this, you might end up with a using last to get out of the subroutine.
use strict ;
use warnings ;
while (<>) {
process_line() ;
do_something() ;
}
sub process_line {
last if /getout/ ;
print "continuing \n" ;
}
This means you are using last where you should be using return and if you have wanings in place you get the error :
Exiting subroutine via last at ..... some file ...
Don't use exit to abort a subroutine if there's any chance that someone might want to trap whatever error happened. Use die instead, which can be trapped by an eval.