Anon Gordon
Anon Gordon

Reputation: 2539

What do Perl functions that return Boolean actually return

The Perl defined function (and many others) returns "a Boolean value".

Given Perl doesn't actually have a Boolean type (and uses values like 1 for true, and 0 or undef for false) does the Perl language specify exactly what is returned for a Boolean values? For example, would defined(undef) return 0 or undef, and is it subject to change?

Upvotes: 12

Views: 4689

Answers (4)

ikegami
ikegami

Reputation: 385809

In almost all cases (i.e. unless there's a reason to do otherwise), Perl returns one of two statically allocated scalars: &PL_sv_yes (for true) and &PL_sv_no (for false). This is them in detail:

>perl -MDevel::Peek -e"Dump 1==1"
SV = PVNV(0x749be4) at 0x3180b8
  REFCNT = 2147483644
  FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x742dfc "1"\0
  CUR = 1
  LEN = 12

>perl -MDevel::Peek -e"Dump 1==0"
SV = PVNV(0x7e9bcc) at 0x4980a8
  REFCNT = 2147483647
  FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x7e3f0c ""\0
  CUR = 0
  LEN = 12

yes is a triple var (IOK, NOK and POK). It contains a signed integer (IV) equal to 1, a floating point number (NV) equal to 1, and a string (PV) equal to 1.

no is also a triple var (IOK, NOK and POK). It contains a signed integer (IV) equal to 0, a floating point number (NV) equal to 0, and an empty string (PV). This means it stringifies to the empty string, and it numifies to 0. It is neither equivalent to an empty string

>perl -wE"say 0+(1==0);"
0

>perl -wE"say 0+'';"
Argument "" isn't numeric in addition (+) at -e line 1.
0

nor to 0

>perl -wE"say ''.(1==0);"


>perl -wE"say ''.0;"
0

There's no guarantee that this will always remain the case. And there's no reason to rely on this. If you need specific values, you can use something like

my $formatted = $result ? '1' : '0';

Upvotes: 12

ErikR
ErikR

Reputation: 52039

It probably won't ever change, but perl does not specify the exact boolean value that defined(...) returns.

When using Boolean values good code should not depend on the actual value used for true and false.

Example:

# not so great code:
my $bool = 0;   #
...
if (some condition) {
  $bool = 1;
}

if ($bool == 1) { ... }

# better code:
my $bool;       # default value is undef which is false

$bool = some condition;

if ($bool) { ... }

99.9% of the time there is no reason to care about the value used for the boolean. That said, there are some cases when it is better to use an explicit 0 or 1 instead of the boolean-ness of a value. Example:

sub foo {
    my $object = shift;
    ...
    my $bool = $object;
    ...
    return $bool;
}

the intent being that foo() is called with either a reference or undef and should return false if $object is not defined. The problem is that if $object is defined foo() will return the object itself and thus create another reference to the object, and this may interfere with its garbage collection. So here it would be better to use an explicit boolean value here, i.e.:

  my $bool = $object ? 1 : 0;

So be careful about using a reference itself to represent its truthiness (i.e. its defined-ness) because of the potential for creating unwanted references to the reference.

Upvotes: 3

user507077
user507077

Reputation:

Since that's the official man page I'd say that its exact return value is not specified. If the Perl documentation talks about a Boolean value then then it almost always talks about evaluating said value in a Boolean context: if (defined ...) or print while <> etc. In such contexts several values evaluate to a false: 0, undef, "" (empty strings), even strings equalling "0".

All other values evaluate to true in a Boolean context, including the infamous example "0 but true".

As the documentation is that vague I would not ever rely on defined() returning any specific value for the undefined case. However, you'll always be OK if you simply use defined() in a Boolean context without comparing it to a specific value.

OK: print "yes\n" if defined($var)

Not portable/future proof: print "yes\n" if defined($var) eq '' or something similar

Upvotes: 3

ysth
ysth

Reputation: 98398

They return a special false value that is "" in string context but 0 in numeric context (without a non-numeric warning). The true value isn't so special, since it's 1 in either context. defined() does not return undef.

(You can create similar values yourself with e.g. Scalar::Util::dualvar(0,"").)

Upvotes: 5

Related Questions