Declaring variables in Perl - perl

I'm learning Perl, and facing some inconsistency between running a program from the command line versus interactively executing it interactively in the debugger.
Specifically, I invoke the Perl debugger with perl -d -e 1, and run this code line-by-line
my $a = 1;
print $a;
$b = 2;
print $b;
In the output I am only seeing the value of $b, while $a seems to be undefined. At the same time, when I execute the same statements with perl myscript.pl, both values are shown in the output. Why does this happen? What am I missing?

The debugger is a wholly different environment from run time Perl. Each line you enter behaves like a separate block, and if you declare a lexical variable like my $a then it will be deleted immediately after the command.
It is as if you had written
{ my $a = 1; }
{ print $a; }
{ $b = 2; }
{ print $b; }
Ordinarily you will declare lexical variables at an appropriate point in the program so that they don't disappear before you need them. But if you want to use the debugger to play with the language then you need to use only package variables, which never disappear and are what you get by default if you don't use my.
Command line "one-liner" Perl programs usually do the same thing, but it's a lesson you will have to unlearn when you come to writing proper Perl programs. You will be using use strict and use warnings at the head of every program, and strict requires that you choose between lexical or package variables by using my or our respectively. If you try to use a variable that you haven't previously declared then your program won't compile.
Also never use $a or $b in your code. Apart from being dreadful variable names, they are reserved for use by the sort operator.
I hope that helps.

Related

Can variable declarations be placed in a common script

Before I start, the whole 'concept' may be technically impossible; hopefully someone will have more knowledge about such things, and advise me.
With Perl, you can "declare" global variables at the start of a script via my / our thus:
my ($a,$b,$c ..)
That's fine with a few unique variables. But I am using about 50 of them ... and the same names (not values) are used by five scripts. Rather than having to place huge my( ...) blocks at the start of each file, I'm wondering if there is a way to create them in one script. Note: Declare the namespace, not their values.
I have tried placing them all in a single file, with the shebang at the top, and a 1 at the bottom, and then tried "require", "use" and "do" to load them in. But - at certain times -the script complains it cannot find the global package name. (Maybe the "paths.pl" is setting up the global space relative to itself - which cannot be 'seen' by the other scripts)
Looking on Google, somebody suggested setting variables in the second file, and still setting the my in the calling script ... but that is defeating the object of what I'm trying to do, which is simply declare the name space once, and setting the values in another script
** So far, it seems if I go from a link in an HTML page to a perl script, the above method works. But when I call a script via XHTMLRequest using a similar setup, it cannot find the $a, $b, $c etc within the "paths" script
HTML
<form method="post" action="/cgi-bin/track/script1.pl>
<input type="submit" value="send"></form>
Perl: (script1.pl)
#shebang
require "./paths.pl"
$a=1;
$b="test";
print "content-type: text/html\n\n";
print "$a $b";
Paths.pl
our($a,
$b,
$c ...
)1;
Seems to work OK, with no errors. But ...
# Shebang
require "./paths.pl"
XHTMLREQUEST script1.pl
Now it complains it cannot find $a or $b etc as an "explicit package" for "script1.pl"
Am I moving into the territory of "modules" - of which I know little. Please bear in mind, I am NOT declaring values within the linked file, but rather setting up the 'global space' so that they can be used by all scripts which declare their own values.
(On a tangent, I thought - in the past - a file in the same directory could be accessed as "paths.pl" -but it won't accept that, and it insists on "./" Maybe this is part of the problem. I have tried absolute and relative paths too, from "url/cgi-bin/track/" to "/cgi-bin/track" but can't seem to get that to work either)
I'm fairly certain it's finding the paths file as I placed a "my value" before the require, and set a string within paths, and it was able to print it out.
First, lexical (my) variables only exist in their scope. A file is a scope, so they only exist in their file. You are now trying to work around that, and when you find yourself fighting the language that way, you should realize that you are doing it wrong.
You should move away from declaring all variables in one go at the top of a program. Declare them near the scope you want to use them, and declare them in the smallest scope possible.
You say that you want to "Set up a global space", so I think you might misunderstand something. If you want to declare a lexical variable in some scope, you just do it. You don't have to do anything else to make that possible.
Instead of this:
my( $foo, $bar, $baz );
$foo = 5;
sub do_it { $bar = 9; ... }
while( ... ) { $baz = 6; ... }
Declare the variable just where you want them:
my $foo = 5;
sub do_it { my $bar = 9; ... }
while( ... ) { my $baz = 6; ... }
Every lexical variable should exist in the smallest scope that can tolerate it. That way nothing else can mess with it and it doesn't retain values from previous operations when it shouldn't. That's the point of them, after all.
When you declare them to be file scoped, then don't declare them in the scope that uses them, you might have two unrelated uses of the same name conflicting with each other. One of the main benefits of lexical variables is that you don't have to know the names of any other variables in scope or in the program:
my( $foo, ... );
while( ... ) {
$foo = ...;
do_something();
...
}
sub do_something {
$foo = ...;
}
Are those uses of $foo in the while and the sub the same, or do they accidentally have the same name? That's a cruel question to leave up to the maintenance program.
If they are the same thing, make the subroutine get its value from its argument list instead. You can use the same names, but since each scope has it's own lexical variables, they don't interfere with each other:
while( ... ) {
my $foo = ...;
do_something($foo);
...
}
sub do_something {
my( $foo ) = #_;
}
See also:
How to share/export a global variable between two different perl scripts?
You say you aren't doing what I'm about to explain, but other people may want to do something similar to share values. Since you are sharing the same variable names across programs, I suspect that this is actually what it going on, though.
In that case, there are many modules on CPAN that can do that job. What you choose depends on what sort of stuff you are trying to share between programs. I have a chapter in Mastering Perl all about it.
You might be able to get away with something like this, where one module defines all the values and makes them available for export:
# in Local/Config.pm
package Local::Config;
use Exporter qw(import);
our #EXPORT = qw( $foo $bar );
our $foo = 'Some value';
our $bar = 'Different value';
1;
To use this, merely load it with use. It will automatically import the variables that you put in #EXPORT:
# in some program
use Local::Config;
We cover lots of this sort of stuff in Intermediate Perl.
What you want to do here is a form of boilerplate management. Shoving variable declarations into a module or class file. This is a laudable goal. In fact you should shove as much boilerplate into that other module as possible. It makes it far easier to keep consistent behavior across the many scripts in a project. However shoving variables in there will not be as easy as you think.
First of all, $a and $b are special variables reserved for use in sort blocks so they never have to be declared. So using them here will not validate your test. require always searches for the file in #INC. See perlfunc require.
To declare a variable it has to be done at compile time. our, my, and state all operate at compile time and legalize a symbol in a lexical scope. Since a module is a scope, and require and do both create a scope for that file, there is no way to have our (let alone my and state) reach back to a parent scope to declare a symbol.
This leaves you with two options. Export package globals back to the calling script or munge the script with a source filter. Both of these will give you heartburn. Remember that it has to be done at compile time.
In the interest of computer science, here's how you would do it (but don't do it).
#boilerplate.pm
use strict;
use vars qw/$foo $bar/;
1;
__END__
#script.pl
use strict;
use boilerplate;
$foo = "foo here";
use vars is how you declare package globals when strict is in effect. Package globals are unscoped ("global") so it doesn't matter what scope or file they're declared in. (NB: our does not create a global like my creates a lexical. our creates a lexical alias to a global, thus exposing whatever is there.) Notice that boilerplate.pm has no package declaration. It will inherit whatever called it which is what you want.
The second way using source filters is devious. You create a module that rewrites the source code of your script on the fly. See Filter::Simple and perlfilter for more information. This only works on real scripts, not perl -e ....
#boilerplate.pm
package boilerplate;
use strict; use diagnostics;
use Filter::Simple;
my $injection = '
our ($foo, $bar);
my ($baz);
';
FILTER { s/__FILTER__/$injection/; }
__END__
#script.pl
use strict; use diagnostics;
use boilerplate;
__FILTER__
$foo = "foo here";
You can make any number of filtering tokens or scenarios for code substitution. e.g. use boilerplate qw/D2_loadout/;
These are the only ways to do it with standard Perl. There are modules that let you meddle with calling scopes through various B modules but you're on your own there. Thanks for the question!
HTH

How to re-declare a variable in the same scope in perl?

Is there a way to re-declare a variable in the same scope using the my keyword in perl? When I run the following script:
use warnings;
use strict;
my $var = 3;
print "$var\n";
undef $var;
my $var = 4;
print "$var\n";
I get the "desired" output, but there is also a warning "my" variable $var masks earlier declaration in same scope. Is there a way to re-declare the variable without getting the warning?
I'm not sure, but I think this is because my happens at compile-time and undef happens at run-time because the warning is being printed even before the first print statement. (I'm not even sure if perl actually compiles the thing before running it.)
Context: I want to be able to copy a chunk of code and paste it multiple times in the same file without having to edit-out all the my declarations. I guess this isn't the best way to do it, but any solution to the problem would be appreciated.
To avoid the warning, you can enclose the new variable declaration, and the code that uses it, inside curly braces ({...}) and create a new scope.
my $var = 3;
print "$var\n";
{
my $var = 4;
print "$var\n";
}

redefining or overloading backticks

I have a lot of legacy code which shells out a lot, what i want to do is add a require or minimal code changes to make the backticks do something different, for instance print instead of running code
i tried using use subs but i couldn't get it to take over backticks or qx (i did redefine system which is one less thing to worry about)
i also tried to make a package:
package thingmbob;
use Data::Dumper;
use overload '``' => sub { CORE::print "things!:\t", Dumper \#_};
#this works for some reason
$thingmbob::{'(``'}('ls');
#this does the standard backtick operation
`ls`
unfourtunatly, I have no experience in OOP perl and my google-fu skills are failing me, could some one point me in the right direction?
caveat:
I'm in a closed system with a few cpan modules preinstalled, odds are that i don't have any fancy modules preinstalled and i absolutely cannot get new ones
I'm on perl5.14
edit:
for the sake of completeness i want to add my (mostly) final product
BEGIN {
*CORE::GLOBAL::readpipe = sub {
print Dumper(\#_);
#internal = readpipe(#_);
if(wantarray){
return #internal;
}else{
return join('',#internal);
}
};
}
I want it to print what its about to run and then run it. the wantarray is important because without it scalar context does not work
This perlmonks article explains how to do it. You can overwrite the readpipe built-in.
EXPR is executed as a system command. The collected standard output of the command is returned. In scalar context, it comes back as a single (potentially multi-line) string. In list context, returns a list of lines (however you've defined lines with $/ (or $INPUT_RECORD_SEPARATOR in English)). This is the internal function implementing the qx/EXPR/ operator, but you can use it directly. The qx/EXPR/ operator is discussed in more detail in I/O Operators in perlop. If EXPR is omitted, uses $_ .
You need to put this into a BEGIN block, so it would make sense to not require, but use it instead to make it available as early as possible.
Built-ins are overridden using the CORE::GLOBAL:: namespace.
BEGIN {
*CORE::GLOBAL::readpipe = sub {
print "#_";
}
}
print qx/ls/;
print `ls`;
This outputs:
ls1ls1
Where the ls is the #_ and the 1 is the return value of print inside the overridden sub.
Alternatively, there is ex::override, which does the same under the hood, but with less weird internals.

Why declare Perl variable with "my" at file scope?

I'm learning Perl and trying to understand variable scope. I understand that my $name = 'Bob'; will declare a local variable inside a sub, but why would you use the my keyword at the global scope? Is it just a good habit so you can safely move the code into a sub?
I see lots of example scripts that do this, and I wonder why. Even with use strict, it doesn't complain when I remove the my. I've tried comparing behaviour with and without it, and I can't see any difference.
Here's one example that does this:
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
my $dbfile = "sample.db";
my $dsn = "dbi:SQLite:dbname=$dbfile";
my $user = "";
my $password = "";
my $dbh = DBI->connect($dsn, $user, $password, {
PrintError => 0,
RaiseError => 1,
AutoCommit => 1,
FetchHashKeyName => 'NAME_lc',
});
# ...
$dbh->disconnect;
Update
It seems I was unlucky when I tested this behaviour. Here's the script I tested with:
use strict;
my $a = 5;
$b = 6;
sub print_stuff() {
print $a, $b, "\n"; # prints 56
$a = 55;
$b = 66;
}
print_stuff();
print $a, $b, "\n"; # prints 5566
As I learned from some of the answers here, $a and $b are special variables that are already declared, so the compiler doesn't complain. If I change the $b to $c in that script, then it complains.
As for why to use my $foo at the global scope, it seems like the file scope may not actually be the global scope.
The addition of my was about the best thing that ever happened to Perl and the problem it solved was typos.
Say you have a variable $variable. You do some assignments and comparisons on this variable.
$variable = 5;
# intervening assignments and calculations...
if ( $varable + 20 > 25 ) # don't use magic numbers in real code
{
# do one thing
}
else
{
# do something else
}
Do you see the subtle bug in the above code that happens if you don't use strict; and require variables be declared with my? The # do one thing case will never happen. I encountered this several times in production code I had to maintain.
A few points:
strict demands that all variables be declared with a my (or state) or installed into the package--declared with an our statement or a use vars pragma (archaic), or inserted into the symbol table at compile time.
They are that file's variables. They remain of no concern and no use to any module required during the use of that file.
They can be used across packages (although that's a less good reason.)
Lexical variables don't have any of the magic that the only alternative does. You can't "push" and "pop" a lexical variable as you change scope, as you can with any package variable. No magic means faster and plainer handling.
Laziness. It's just easier to declare a my with no brackets as opposed to concentrating its scope by specific bracketing.
{ my $visible_in_this_scope_only;
...
sub bananas {
...
my $bananas = $visible_in_this_scope_only + 3;
...
}
} # End $visible_in_this_scope_only
(Note on the syntax: in my code, I never use a bare brace. It will always tell you, either before (standard loops) or after what the scope is for, even if it would have been "obvious".
It's just good practice. As a personal rule, I try to keep variables in the smallest scope possible. If a line of code can't see a variable, then it can't mess with it in unexpected ways.
I'm surprised that you found that the script worked under use strict without the my, though. That's generally not allowed:
$ perl -E 'use strict; $db = "foo"; say $db'
Global symbol "$db" requires explicit package name at -e line 1.
Global symbol "$db" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl -E 'use strict; my $db = "foo"; say $db'
foo
Variables $a and $b are exempt:
$ perl -E 'use strict; $b = "foo"; say $b'
foo
But I don't know how you would make the code you posted work with strict and a missing my.
A sub controls/limits the scope of variables between the braces {} that define its operations. Of course many variables exist outside of a particular function and using lexical my for "global" variables can give you more control over how "dynamic" their behavior is inside your application. The Private Variables via my() section of perlodocperlsub discusses reasons for doing this pretty thoroughly.
I'm going to quote myself from elsewhere which is not the best thing to do on SO but here goes:
The classic perlmonks node - Variable Scoping in Perl: the
basics - is a frequently
consulted reference :-)
As I noted in a comment, Bruce Gray's talk at YAPC::NA 2012 - The why of my() is a good story about how a pretty expert perl programmer wrapped his head around perl and namespaces.
I've heard people explain my as Perl's equivalent to Javascript's var - it's practically necessary but, Perl being perl, things will work without it if you insist or take pains to make it do that.
ps: Actually with Javascript, I guess functions are used to control "scope" in a way that is analagous to your description of using my in sub's.

Perl eval command not working as expected

I have a sort of perl "terminal" (pastebin code) we'll call it that I've written, the idea behind writing it is I wanted to run perl code line by line, allowing me to run new commands on existing (large) data sets, without having to change a script and reload the data set and re-run my script.
(Mind you, I wrote this almost a year ago now, and it was mostly a learning experiment (with a dynamic function tablet), however now I have some use for it and discovered some issues which are preventing me from utilising it.)
As such, I eval user entered commands, however, they aren't behaving as expected and perhaps someone can shed some light on why this would be.
This is the 'important' bit, I have the command line data stored in #args, and the first element of that is stored in $prog. I check if there's an existing function (I allow users to create functions, and really abuse references to get an action table) if not I try and eval the command.
if(exists($actions{$prog})){
print "\n";
$actions{$prog}->(#args);
print "\n";
}else{
print "\nEVALing '$command'\n";
eval $command;
warn $# if $#;
print "\n";
}
As can be seen below, it works as expected for the assignment of scalars, but fails with the assignment of arrays and hashes.
user#host:~/$ perl term.pl
1358811935>$a = 0;
EVALing '$a = 0;'
1358811937>print $a;
EVALing 'print $a;'
0
1358811944>#b = qw(2 3);
EVALing '#b = qw(2 3);'
Global symbol "#b" requires explicit package name at (eval 5) line 1.
1358811945>print #b;
EVALing 'print #b;'
Global symbol "#b" requires explicit package name at (eval 6) line 1.
1358812008>my #b = qw(2 3);
EVALing 'my #b = qw(2 3);'
1358812008>print "#b";
EVALing 'print "#b";'
Possible unintended interpolation of #b in string at (eval 9) line 1.
Global symbol "#b" requires explicit package name at (eval 9) line 1.
1358812016>print join(',',#b);
EVALing 'print join(',',#b);'
Global symbol "#b" requires explicit package name at (eval 10) line 1.
1358812018>
Variables $a and $b are special, because they are used by sort. Therefore, strict does not complain if they are not declared. Using $x would trigger the same error as arrays and hashes.
For this kind of thing, you probably want to allow arbitrary package variables to be used by saying no strict 'vars';. Declaring a lexical (my) variable in the eval'd code will work, but will no longer be in scope for the next eval.
Alternatively, pre-declare a set of variables for the eval'd code to use (perhaps including a %misc hash).
A completely different approach is to each time through eval a concatenation of all the code entered so far (if printing output is a factor, redirecting output up until the most recent code entered).