in reply to detecting an undefined variable

It may be a bit late, but I finally understand your problem. It has nothing to do with symbolic reference. Sorry about that confusion. You want to initialize the variable $myscale with the value of $scale (if it is defined) and with '1' otherwise. Normally you would do this:
my $myscale = $scale // 1;

The problem is that $scale may be not defined because it is not declared. The code above causes a compile time error.

The following code incorporates many of replies you have already received. Note that the same code must work in three situations. It is tempting to write the code as a function and call it wherever it is needed. This does not always work correctly because it would be testing declare and define in the scope of the function, not of the call.

use strict; use warnings; use Test::Simple tests => 3; { # $scale is not declared my $myscale = do{ use strict 'vars'; no warnings 'uninitialized'; (do{eval '$scale'; $@} ) ? 1 : (eval '$scale') // 1; }; ok( $myscale == 1, 'not declared'); } my $scale; { # $scale declared, but not defined my $myscale = do{ use strict 'vars'; no warnings 'uninitialized'; (do{eval '$scale'; $@} ) ? 1 : (eval '$scale') // 1; }; ok( $myscale == 1, 'declared, but not defined'); } $scale = 7; { # $scale declared, and defined my $myscale = do{ use strict 'vars'; no warnings 'uninitialized'; (do{eval '$scale'; $@} ) ? 1 : (eval '$scale') // 1; }; ok( $myscale == $scale, 'defined'); }

The logic is confusing. The first eval compiles the string '$scale' recognizing it as a variable. If it is not declared, this is an error under 'no strict vars'. That error is signaled with the system variable $@. Because $@ is the last value in the do-block, it is returned. We only care about its logical value. "True" means that there was an error and the variable is not declared. We return the default value (1). "False" means there was no error, the variable is declared. At this point we would like to do the normal assignment, but our code has to compile in all three cases. We call eval again. We know that there will not be an error. This time, we want the return value (the value of the variable). If that value is undef, we use the default value. The result of all this logic is returned by the outer do and assigned to $myscale.

Bill

Replies are listed 'Best First'.
Re^2: detecting an undefined variable
by LloydRice (Beadle) on Sep 24, 2019 at 11:36 UTC

    Thanks, Bill. That's exactly what I need.

    Lloyd

      Now I will admit a little secret. The second method in your original post would work under
      no strict 'vars'; no warnings 'once';

      Without strict, if a variable '$state' is not already declared, perl will automatically declare a package variable '$state'. Of course this variable would not be defined so perl would assign your '1' to $mystate. This could lead to a very subtle bug if in the future you ever tried to declare a lexical variable '$state'. It is legal to have two variables with the same name. Hard to tell which one perl will think you mean.

      Bill
        The second method in your original post would work under

            no strict 'vars';
            no warnings 'once';

        Indeed, something similar to this will quietly work even with all strictures and warnings enabled if fully-qualified package-global names are used (e.g., $main::scale or its shorthand version $::scale):

        c:\@Work\Perl\monks>perl -MData::Dump -le "use strict; use warnings; ;; my $scale = $::scale // 42; print $scale; dd $::scale; " 42 undef
        If fully-qualified names are used, Perl is perfectly clear about who's who and what's what although as you say, it can be hard for the programmer to understand the prevailing state of affairs. (The trick of course is that $scale is not the same name as either $main::scale or $::scale.)


        Give a man a fish:  <%-{-{-{-<