Is the truthiness of a dualvar always that of its string part?
Asked Answered
R

2

11

The empirical behaviour of my Perl 5.26.2 x64 (Cygwin) is that a dualvar is truthy if and only if its string part is truthy:

# Falsy number, truthy string => truthy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 0, "foo"; say "yes" if $v'
yes

# Truthy number, falsy string => falsy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 1, ""; say "yes" if $v'

# Truthy number, truthy string => truthy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 1, "foo"; say "yes" if $v'
yes

# Falsy number, falsy string => falsy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 0, ""; say "yes" if $v'

This has been the case since 2009 per this.

Question: Is this guaranteed behaviour?

  • Boolean::String says that this is the behaviour. However, I don't know if that's something I can rely on, in terms of backward compatibility. I also do not see an express statement in perlsyn, Scalar::Util, or perldata#Context.

  • I do see the following in perldata#Scalar-values:

    A scalar value is interpreted as FALSE in the Boolean sense if it is undefined, the null string or the number 0 (or its string equivalent, "0"), and TRUE if it is anything else. The Boolean context is just a special kind of scalar context where no conversion to a string or a number is ever performed.

    The statement that "no conversion ... is ever performed" unfortunately doesn't tell me which part(s) of a dualvar the interpreter is looking at!

  • Similarly, Chas. Owens's related answer says that

    the truthiness test looks at strings first

    But if it looks at strings first, what does it look at second, and when?

Edit My understanding is that if overload is defined on a variable, dualvar or not, the bool overload will control. I am wondering about the non-overloaded case.

Edit 2 ikegami's answer here points out that PL_sv_yes and PL_sv_no also have an NV (double) component. For bonus points :) , does the NV have any effect on truthiness if a dualvar has one? (Let me know if that answer is actually involved enough to deserve a separate question.)

Rriocard answered 2/1, 2019 at 18:25 Comment(2)
This is the best researched question that I can recall seeing.Valedictorian
@Valedictorian Thanks for your answer, and for the compliment!Rriocard
I
7

Yes, at least so far. The SvTRUE_common macro is usually used to decide where an SV is "true" in a boolean context. Here's how it is defined in sv.h in the perl 5.26.1 source:

#define SvTRUE_common(sv,fallback) (            \
      !SvOK(sv)                     \
    ? 0                     \
    : SvPOK(sv)                     \
    ? SvPVXtrue(sv)                 \
    : (SvFLAGS(sv) & (SVf_IOK|SVf_NOK))         \
    ? (   (SvIOK(sv) && SvIVX(sv) != 0)     \
       || (SvNOK(sv) && SvNVX(sv) != 0.0))      \
    : (fallback))

After the scalar passes the SvOK test (whether it is defined), the next check is SvPOK -- whether the scalar has a valid internal string representation. Dualvars always pass this check, so the boolean test of a dualvar is whether its string representation is true (SvPVXtrue(...)).

The code is different in perl 5.6.2

I32
Perl_sv_true(pTHX_ register SV *sv)
{
    if (!sv)
        return 0;
    if (SvPOK(sv)) {
        register XPV* tXpv;
        if ((tXpv = (XPV*)SvANY(sv)) &&
                (tXpv->xpv_cur > 1 ||
                (tXpv->xpv_cur && *tXpv->xpv_pv != '0')))
            return 1;
        else
            return 0;
    }
    else {
        ...

but the logic is the same -- check SvPOK first and then return whether the string representation is not empty and not equal to "0".

I would think future generations of Perl developers would be wary of changing this long-standing logic.

Irby answered 2/1, 2019 at 22:37 Comment(2)
I think the reason is that a string like abc (which is true) numifies to 0 (which is false). So if a scalar contained a string and its numification, checking the string ensures the correct outcomePretorius
mob, thanks for the details! Thanks also for mob-rule.com, which is very cool!Rriocard
V
2

Question: Is this guaranteed behaviour?

This boils down to how a scalar is tested in the Boolean context, as string or numeric?

In Perl the documentation is the closest thing to a standard. So if there is no statement in docs then the formal answer must be: No, it is not "guaranteed behaviour".

Since the docs come tantalizingly close a few times, talking about that context and conversions, and yet specifically do not spell out which test is done I'd say that this must indeed be taken as an implementation detail. You cannot "rely" on it.

If strict reliability is needed one solution is a simple class that ensures to test what you need.

In more practical terms, it appears that in if ($v) it is the string part that is tested, and if it's not there then a numeric test goes (without the actual conversion as the docs say). As you ask about variables that have been set as dualvar then for those it's going to be the string test.

Valedictorian answered 2/1, 2019 at 20:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.