w8lle has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!

I am running Perl v5.10.0 (built for x86_64-linux-thread-multi) and I have an issue with the "defined" function. I am not sure this is actually a fault, but it have worked in previously releases (unfortunately I don't know which).

The issue seems to happen when I've got a defined variable without a value, e.g. $var1 = "".

If I need to check if (one of) two variables are defined, I need to do that like this:

if (defined $var1 || defined $var2) if (defined $var1 && defined $var2)

While I've previously been able to do it like this:

if (defined ($var1 || $var2)) if (defined ($var1 && $var2))

Running the following fails for both OR and AND (test 1 and 3):

./test.pl "" Test 1: NOK Test 2: OK Test 3: OK Test 4: NOK

When test.pl contains:

#!/usr/bin/perl use strict; use warnings; for my $i (1 .. 4) { my $result = (&successfulValidation ($i))? "OK": "NOK"; print "Test ", $i, ": ", $result, "\n"; } sub successfulValidation { my $test = shift; if ($test == 1) { return defined ($ARGV[0] || $ARGV[1]); } elsif ($test == 2) { return defined $ARGV[0] || defined $ARGV[1]; } elsif ($test == 3) { return defined ($ARGV[0] && $ARGV[1]); } elsif ($test == 4) { return defined $ARGV[0] && defined $ARGV[1]; } }

The following works just fine, though, so maybe the first (and only) variable to check can't be empty!?

./test.pl "" ""

Is it a bug that test 1 and test 3 fail? I mean, test 1 should have returned TRUE ($ARGV[0] was defined, although with an empty value) and test 3 should have returned "FALSE" ($ARGV[1] wasn't defined)? Maybe I am using "defined" in the wrong way!?

Many thanks in advance,

/Johan

Replies are listed 'Best First'.
Re: "defined" function fails to evaluate expression; feature or fault?
by stevieb (Canon) on Jan 26, 2017 at 20:50 UTC

    It's not a feature or bug, it just is :)

    defined() returns a bool, (either false/true) when it evaluates something, so when you do this: defined ($x || $y);, it's not doing what you think it does.

    Here's an example that illustrates the issue:

    perl -wMstrict -E 'my $x = defined $ARGV[5]; say defined $x' 1

    Now, $ARGV[5] is not set in any way, but since we're returning the value of the call to $x, $x will most definitely be defined, because it now evaluates to false as the variable was not defined (define() returns false, if something wasn't defined).

    You need to call a define on each side of the comparison operator:

    my $x = defined $x || defined $y;

    ...as per your solutions that work. Then, check $x for truth:

    die "blah...\n" if ! $x;

    ...or combined:

    die "blech...\n" if ! defined $x || defined $y;

      Not that it makes any difference in this case, but defined returns  '' (the empty string; false) or  1 (true):

      c:\@Work\Perl>perl -wMstrict -le "print 'perl version ', $]; ;; print 'undefined A: >', defined(), '<'; print 'undefined B: >', defined(undef), '<'; print 'defined: >', defined(42), '<'; " perl version 5.008009 undefined A: >< undefined B: >< defined: >1< perl version 5.014004 undefined A: >< undefined B: >< defined: >1<


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

        Hi AnomalousMonk,

        defined returns '' (the empty string; false) or 1 (true)

        To be even more specific, Perl has a "special" value for "false" - see Truth and Falsehood.

        The difference between an empty string and the special "false" value:

        $ perl -wMstrict -le 'my $x=""; print 3+$x;' Argument "" isn't numeric in addition (+) at -e line 1. 3 $ perl -wMstrict -le 'my $x=!!""; print 3+$x;' 3 $ perl -wMstrict -le 'my $x=defined(); print 3+$x;' 3

        And looking even more closely with Devel::Peek:

        Regards,
        -- Hauke D

        Update 2019-08-17: Updated the link to "Truth and Falsehood".

        Yep, I caught that after doing some testing, and had updated my reply (at least I thought I fixed it all).

        Thanks for the heads-up, as if someone is expecting a zero and is getting the empty-string type false instead, it could cause head-scratching.

Re: "defined" function fails to evaluate expression; feature or fault? (truth)
by Anonymous Monk on Jan 26, 2017 at 20:35 UTC
Re: "defined" function fails to evaluate expression; feature or fault?
by w8lle (Novice) on Jan 27, 2017 at 06:07 UTC

    OK, so I actually WAS using defined in the wrong way! :-(

    Many thanks for the prompt response...