How to check if variable is declared in perl?
Asked Answered
L

9

9

I am using use strict; in perl and with that I use the following statement.

unless(defined($x)){
      print "Not defined";
}

Where $x is not declared anywhere. So I expect it to print "Not defined" but it returns an error

Global symbol "$x" requires explicit package name at *********** in line 15.
Livvi answered 21/8, 2010 at 11:0 Comment(2)
Why would you want to do this? Code should be already aware of what variables and namespaces it has available to it -- there should not be a need to check.Volscian
@Volscian there are many reasons. It's similar to #define <> in C. You want to say filter out debug print statements in your codeSoukup
O
19

The strict pragma has three parts: strict references, strict variables, and strict subs. The one you're running into is

strict vars

This generates a compile-time error if you access a variable that wasn't declared via our or use vars, localized via my, or wasn't fully qualified. Because this is to avoid variable suicide problems and subtle dynamic scoping issues, a merely local variable isn't good enough.

Because it generates compile-time errors, your non-BEGIN code won't even have a chance to run. You can temporarily allow non-strict variables inside a block as in

{
  no strict 'vars';
  print "Not defined!\n" unless defined $x;
}

but note that Perl's defined operator tells you whether a value is defined, not whether a variable has been declared.

Tell us more about your application, and we can give you better advice about how to handle it.

Oud answered 21/8, 2010 at 11:7 Comment(1)
The important part is the distinction between undeclared and undefined.Pyrogenic
D
6

You can't even refer to a variable unless it's declared. When you ask

defined( $x ) ?

the compiler is going to complain: I don't know this what you're asking about, how am I supposed to tell it is defined? It has no point of reference for that variable, since you've indicated you do not want variables auto-created by name.

If strict 'vars' was not on--which it is by default when you use strict--then it would create an entry in the package symbol table for 'x'.

Interestingly enough is that without strict 'refs' it is also easy to check if a variable is in the package symbol table.

defined( *{ __PACKAGE__ . '::x' }{SCALAR} )

Since there is no way to auto-create a lexical ("my variables"), there is also not a standard way to check to see if lexicals are declared. Lexical variables are stored in the "pad". But there is a module PadWalker that can help.

In order to check the current level, you could get a hash of the pad, and then check whether or not it exists in the current pad. You could also loop back up through the stack (the integer argument works something like caller) to find where the most recent x was.

my $h = peek_my (0);
exists $h->{x};
Depone answered 21/8, 2010 at 18:38 Comment(0)
F
6

I think you are mixing 'defined' and 'declared' concepts.

Your are asking for 'How to check if variable is declared in perl' but then you are checking if a variable is defined. These are two different concepts.

In perl if you use 'use strict' you are automatically checking for any variable not declared (using my, local or our). Once you have a variable declared, you can test if it is defined (have a value assigned).

So in your test, you are missing a prior declaration before testing for defineness

use strict;
my $x;  # you are missing this part
[...] | # code
# your test for define
print defined $x? "defined\n" : "not defined\n";

Please be aware the testing for only $x is incorrect for your purpose:

my ($x,$y, $z);
$w;         # not declared (use strict will catch it and die)
$x = 0;     # declared and defined BUT if you make a logic test like 'if ($x) {}' then it will be FALSE, so don't confuse testing for **'$x'** and testing for **'defined $x'**
$y = undef; # declared but not defined
$z = 1;     # declared, defined, and logial test TRUE

Finally the answer of xenorraticide seems faulty to me: he suggest 'unless $x' that is not correct for testing if defined as I said before. He also suggest 'unless exists $x', that is wrong for testing scalars. 'exists' test is only for hashes keys (and deprecated for arrays).

Hope this helps.

Funicular answered 22/8, 2010 at 2:2 Comment(0)
P
1
 #
 print "Not defined" if !defined($x);

result will be

Not defined

 #
 use strict;
 print "Not defined" if !defined($x);

will generate error as in your question.

Look to: http://perldoc.perl.org/strict.html, where described how you can import only required restrictions. (However use strict 'vars' is very good idea :) )

Precautious answered 21/8, 2010 at 11:9 Comment(0)
S
1

Normally this kind of code should not be required for a serious program, but still why not just for fun: (assuming use strict)

print "Not defined\n" unless eval 'ref(\$x)';
Steal answered 6/11, 2012 at 14:29 Comment(0)
S
1

It seems you can check whether a variable is declared (as described under "Symbol Tables" in man perlmod) like this:

main::(-e:1):   1
  DB<1> x __PACKAGE__
0  'main'
  DB<2> x exists ${__PACKAGE__ . '::'}{xyz}
0  ''
  DB<3> $xyz = undef
  DB<4> x exists ${__PACKAGE__ . '::'}{xyz}
0  1
  DB<5> $xyz = 7
  DB<6> x exists ${__PACKAGE__ . '::'}{xyz}
0  1

So after perl -d -e 1 you are in package main with $xyz not being declared. Thus ("global") xyz does not exist in the symbol table of main. However after assigning undef to a variable of that name, there is an entry in the symbol table for it.

Still that mechanism does not work for my variables (lexically scoped).

Stickleback answered 28/2, 2023 at 10:10 Comment(0)
O
0
#!/usr/bin/perl -l

use strict;

# if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
#my $lol = 'eeeeeeeeeee' ;
# no errors or warnings at any case, despite of 'strict'

our $lol = eval {$lol} || 'lol' ;

print $lol;
Owings answered 16/5, 2013 at 8:8 Comment(0)
O
0

my solution is #!/usr/bin/perl -l

use strict;

# if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
#my $lol = 'eeeeeeeeeee' ;
# no errors or warnings at any case, despite of 'strict'

our $lol = eval {$lol} || 'lol' ;

print $lol;
Owings answered 16/5, 2013 at 8:26 Comment(0)
F
-1

You can use unless, like this:

use 'strict';

my $var = 'defined';
unless (defined($var)) {
  print "not defined\n";
}

$var = undef;
unless (defined($var)) {
  print "not defined\n";
}

The first print will not print anything, the second one will since $var has been made undef.

Frecklefaced answered 31/12, 2020 at 3:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.