in reply to detecting an undefined variable

The Perl definition of many common words is not quite what you think. The question which you meant to ask is "How can I tell if a variable is 'declared'"? 'Defined' means that a variable has a value. This makes no sense if it is not 'declared'. 'Exists' refers to keys in a hash and has nothing to do with variables. The concept of storing the name of a variable in another variable is called 'symbolic reference'. It is never needed and always discouraged. In fact, one advantage of 'use strict' is that it prevents us from using symbolic reference by accident. To return to your original question, there is no run-time support to test if a variable is 'declared' ('Use strict' provides compile-time support). This would only be useful with symbolic reference which you should not be using anyhow.

UPDATE: I took it as a challenge to do what you asked for using strict vars with eval.

use warnings; use Test::Simple tests => 3; # Test wether or not the target of a symbolic reference is declared. my $xxx ; our $yyy; { use strict vars; my $sym_ref; $sym_ref = '$xxx'; ok ( do{eval $sym_ref; !$@}, 'declared lexical'); $sym_ref = '$yyy'; ok ( do{eval $sym_ref; !$@}, 'declared package'); $sym_ref = '$zzz'; ok (!do{eval $sym_ref; !$@}, 'not declared'); # Note: !do..... }

This test does what you wanted, but not what you need because symbolic-refs only work with package variables. Of course once you know that the variable is declared, you could use LanX's idea and check if the name 'exists' in the symbol table. Even that could fail in special cases. DO NOT USE SYMBOLIC REFERENCE!

Bill

Replies are listed 'Best First'.
Re^2: detecting an undefined variable
by LanX (Saint) on Sep 21, 2019 at 16:28 UTC
    I mostly agree, but

    > Exists refers to keys in a hash and has nothing to do with variables.

    this statement is problematic because Perl's namespaces - including scratchpads° - are actually implemented as hashes.

    for instance it's perfectly possible to check the STASH for a package variable

    DB<3> p exists $main::{xxx} DB<4> $xxx = 1 DB<5> p exists $main::{xxx} 1

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

    °) though you'd need PadWalker to access it.

      That doesn't check if the variable exists though, it checks if the stash for that name is populated with anything. Having a sub or file handle with the same name would cause the stash entry to exist, usually stored inside a GLOB. While the other types can be detected, it isn't possible to distinguish between an undefined and non-existent scalar by inspecting a GLOB in pure perl.

        You are right, exists doesn't work reliably on glob-slots. :/

        I should have known better, already got bitten by it in the past.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      Thanks for all the replies to my "detecting an undefined ..". I agree with the last reply, that I meant "declared" rather than "defined". It's not clear to me why what I'm trying to do should be so undisciplined (ill advised?). I often put together pieces of code from various places. So it's handy to check whether some variable already exists in another piece. In the example I gave, the code would be in a function being called from some other code, written at a different time. If I had then used a variable called $scale, it would be handy to know whether that variable existed in the calling code or whether I now had to declare and define it anew. If it existed before, I would want to use the existing value. If not, I would define it as
      my $scale = 1;
      That doesn't seem so undisciplined to me.
        > That doesn't seem so undisciplined to me.

        It's fragile and opens the door to many hard to debug potential problems.

        Though most people were interpreting your intention as trying to use $$symbolic dereference. That's why I asked for more context.

        Using hashes for optional values is a common pattern.

        > I often put together pieces of code from various places.

        Well, the common pattern for that class of problems is to use modules with stable APIs.

        If you really want to do code generation by composing code chunks, then consider using package declarations and inspecting an our $scale variable in the STASH

        use strict; use warnings; package Chunk; #our $scale =42; package main; my $myscale = $Chunk::{scale} // 1; print $myscale;

        but now that you use packages you're only one step away of using modules ...

        HTH! :)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice