views:

75

answers:

1

I've run into a situation (while logging various data changes) where I need to determine if a reference has a valid string coercion (e.g. can properly be printed into a log or stored in a database). There isn't anything in Scalar::Util to do this, so I have cobbled together something using other methods in that library:

use strict;
use warnings;

use Scalar::Util qw(reftype refaddr);

sub has_string_coercion
{
    my $value = shift;

    my $as_string = "$value";
    my $ref = ref $value;
    my $reftype = reftype $value;
    my $refaddr = sprintf "0x%x", refaddr $value;

    if ($ref eq $reftype)
    {
        # base-type references stringify as REF(0xADDR)
        return $as_string !~ /^${ref}\(${refaddr}\)$/;
    }
    else
    {
        # blessed objects stringify as REF=REFTYPE(0xADDR)
        return $as_string !~ /^${ref}=${reftype}\(${refaddr}\)$/;
    }
}

# Example:
use DateTime;
my $ref1 = DateTime->now;
my $ref2 = \'foo';

print "DateTime has coercion: " . has_string_coercion($ref1) . "\n\n";
print "scalar ref has coercion: " . has_string_coercion($ref2) . "\n";

However, I suspect there might be a better way of determining this by inspecting the guts of the variable in some way. How can this be done better?

+5  A: 

From perldoc overload:

overload::StrVal(arg)

Gives string value of arg as in absence of stringify overloading.

sub can_stringify {
    my ($obj) = @_;
    return "$obj" ne overload::StrVal($obj);
}

Note that overload::Method is not appropriate here because:

  1. 'bool', '""', '0+',

If one or two of these operations are not overloaded, the remaining ones can be used instead.

Therefore, checking only if '""' is overloaded would return false negatives compared to the method you show in your question.

Sinan Ünür
I liked your earlier version better, that showed how to find the stringification method -- e.g. `perl -MDateTime -Moverload -wle'my $dt = DateTime->now; my $method = overload::Method($dt, q{""}); print $method->($dt)'` :)
Ether
@Ether The problem is that `bool` might have been overloaded providing a stringification without `'""'` being overloaded.
Sinan Ünür