http://www.perlmonks.org?node_id=844336

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

Greetings,

Given a stringified referent, how does one dereference it? IE: What does sub f need to be so that the results from (2) match the results from (1)?

Many thanks!
#! use Data::Dumper; use strict; use warnings; sub f { # (0) # }; my $str; my $ref=[1,2]; print Data::Dumper->Dump([\$ref],[qw(*ref)]); # (1) $str=''.$ref; print Data::Dumper->Dump([\$str],[qw(*str)]); # what do I need to do to $str so that (2) dump the original data stru +cture my $newref=f($str); print Data::Dumper->Dump([\$newref],[qw(*newref)]);# (2)
edited to remove {} block

Replies are listed 'Best First'.
Re: dereferencing a stringfied referent
by almut (Canon) on Jun 12, 2010 at 09:47 UTC

    You can't, at least not easily. Sure, you could write some XS code that puts the address back into the RV field of a reference, but you're not meant to mess with addresses like in C.  It's asking for trouble, because Perl manages memory via reference counts1. And what if the item your stringified "reference" points to no longer exists when you dereference it?

    What is the real problem you're trying to solve, for which you would need this functionality?

    ___

    1 those reference counts are automatically incremented/decremented as needed as long as you use normal Perl references, but they're not updated for stringified references.

      Hi,

      I'm working with a SIG{__WARN__} and I'm calling Carp::Longmess. By default, I'm getting those lovely stringified referents which I want. But I also need to get the data structures those stringified referents dereference to.

      I suppose I could get Carp::Longmess to expand out the un blessed data structures then capture them via "regex", but I was hoping that there was a cleaner way.

      This kind of gets me what I'm after without actually dereferencing the stringified referent. The replacement format_arg is "stashing" the stringified data structure while returning its stringified referent
      #! use Carp::Heavy; use Data::Dumper; use Scalar::Util; use strict; use warnings; my @stash; BEGIN { # Now redefine Carp::format_arg so we can dump refs too! no warnings qw(once redefine); *Carp::format_arg = sub { # shameless stolen from b. d foy package Carp; my $arg_s=shift; my $return_s; if (not defined $arg_s) { $return_s='undef'; } elsif (Scalar::Util::blessed($arg_s)) { # an object $return_s="'".ref($arg_s)."(object/class)'"; } elsif (ref($arg_s)) { # a ref require Data::Dumper; local $Data::Dumper::Indent=0; local $Data::Dumper::Terse=0; # deparse CodeRefs local $Data::Dumper::Deparse=ref($arg_s) eq 'CODE'; $return_s=Data::Dumper::Dumper($arg_s); $return_s=~ s/^\$VAR\d+\s*=\s*//; $return_s=~ s/;\s*$//; $return_s=~ s/ */ /g if (ref($arg_s) eq 'CODE'); push(@stash,$return_s); $return_s="'$arg_s($#stash)'"; } else { $return_s=$arg_s; $return_s=~ s/'/\\'/g; $return_s=str_len_trim($arg_s,$Carp::Heavy::MaxArgLen); $return_s="'$arg_s'" unless $arg_s =~ /^-?[\d.]+\z/; } $return_s=~ s/([[:cntrl:]]|[[:^ascii:]])/sprintf("\\x{%x}",ord +($1))/eg; return $return_s; }; }; # BEGIN: $SIG{__WARN__}=sub { my $buffer=Carp::longmess(); print STDOUT "$buffer\n"; print STDOUT "$_: $stash[$_]\n" for (0..$#stash); @stash=(); }; # Just some code to test use CGI; my $q=CGI->new(); main(1,[2],{3=>$q},sub { return "huh" },$q); sub main { warn "main"; shift; shift; subroutine(@_); }; sub subroutine { warn "sub"; die "just for fun!"; };
      It yields:
      at Dump.pl line 62 main::main(1, 'ARRAY(0x1bba4ec)(0)', 'HASH(0x1b58b5c)(1)', 'CO +DE(0x1a6d4a4)(2)', 'CGI(object/class)') called at Dump.pl line 59 0: [2] 1: {'3' => bless( {'.parameters' => [],'use_tempfile' => 1,'.charset' +=> 'ISO-8859-1','.fieldnames' => {},'param' => {},'escape' => 1}, 'CG +I' )} 2: sub { use warnings; use strict 'refs'; return 'huh';} at Dump.pl line 68 main::subroutine('HASH(0x1b58b5c)(0)', 'CODE(0x1a6d4a4)(1)', ' +CGI(object/class)') called at Dump.pl line 64 main::main(1, 'ARRAY(0x1bba4ec)(2)', 'HASH(0x1b58b5c)(3)', 'CO +DE(0x1a6d4a4)(4)', 'CGI(object/class)') called at Dump.pl line 59 0: {'3' => bless( {'.parameters' => [],'use_tempfile' => 1,'.charset' +=> 'ISO-8859-1','.fieldnames' => {},'param' => {},'escape' => 1}, 'CG +I' )} 1: sub { use warnings; use strict 'refs'; return 'huh';} 2: [2] 3: {'3' => bless( {'.parameters' => [],'use_tempfile' => 1,'.charset' +=> 'ISO-8859-1','.fieldnames' => {},'param' => {},'escape' => 1}, 'CG +I' )} 4: sub { use warnings; use strict 'refs'; return 'huh';} just for fun! at Dump.pl line 69.
Re: dereferencing a stringfied referent
by LanX (Saint) on Jun 12, 2010 at 12:13 UTC
    Hi

    As almut already told you there is no clean straight forward solution.

    These kind of problems normally originate from trying to use a reference as hash key...there are moduls with specially tied hashes to handle this.

    Their basic solution is to memorize the relation in a look-up-table, whenever a stringification is needed.

    $ref_of{$stringification}=$reference;

    Keep in mind that the refcounter is automatically incremented as long as the table entry exists, this could lead to new problems if you don't take care about memory consumption...

    Cheers Rolf

      Thank you!
Re: dereferencing a stringfied referent
by sflitman (Hermit) on Jun 12, 2010 at 17:52 UTC
    I've also been curious about this. I've had to convert references to YAML or JSON and output to a log file, but I agree where this becomes a big issue is where the stringified referent is being used as a hash key. Could anyone inform me if it is reasonable to use a JSON encoded version of the referenced object as a hash key instead of a stringified referent?

    SSF