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

Monks, Saints and the like,

consider this piece of code:

my @aha = (1,2,3,4,5); my $ref = \@aha; my $ref2="$ref"; print "@$ref\n"; print ref($ref), " $ref\n"; print ref($ref2)," $ref2\n";
This shows best the current problem I'm facing. I have an interpolated reference within a scalar. If I retrieve it, the ref operator does not recognize it as reference anymore. My question is: a) After such an interpolation happens - is the object the reference is/was pointing to destroyed if this was the last reference (before interpolation). (Only then b makes sense)

b) how could I raise the interpolated reference from the dead so that it would be recognized as a reference (could do with regexp - brrr) and that I can really use it as such.

Quite franky I expect the answer "Your code is broken". :-)

Bye
 PetaMem

Replies are listed 'Best First'.
Re: Recovering References from Interpolation
by Ovid (Cardinal) on Jun 10, 2002 at 14:31 UTC

    Once you "stringify" a reference, you have fundamentally changed the nature of the data that the scalar refers to. It's now a string, not a reference. As for your second question, no, you can not get at the data once associated with the reference. You play around with Devel::Pointer, but that shouldn't be used for anything serious.

    You also asked if the object the reference pointed two was destroyed after the interpolation. The answer is "no". Interpolating a reference does not affect the reference count, nor does assigning the interpolation affect it.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: Recovering References from Interpolation
by Joost (Canon) on Jun 10, 2002 at 14:40 UTC
    An interpolated reference is just a string. There is no way to change it back to a real reference (well... you could probably hack around with XS or Inline::C) and if it was the last reference to an object the object will get lost.

    The only problem I have with that is why you would do something like this anyway:

    my $ref = Object->new(); $ref = "$ref"; # overwrite $ref: destroy object
    Is there any use for this? If you really want a stringified reference, you can always make a copy (ie:)
    my $ref = Object->new(); my $refstring = "$ref"; # keep object in $ref
    Update: Just a reminder: you can not restore a pointer to a destroyed object without serious memory leeks / core dumps and other unpleasantness, so IF the object is still in memory, you still have another reference laying about somewhere - then you CAN get your reference back.
    #!/usr/bin/perl -w use strict; use vars qw($ref); $ref = [1,2,3,4]; print join(',',@$ref)."\n"; my $string = "$ref"; #print join(',',@$string)."\n"; # this does not work my $getref = unstringify($string) || die "Cannot find ref!"; print join(',',@$getref)."\n"; sub unstringify { # works only on globals in package main ! # but you could also use another hash # ( instead of %main:: ) my $string = shift; for (keys %{main::}) { my $value; next unless $value = ${${main::}{$_}}; next unless ref($value); next unless $value eq $string; # implicit stringification return $value; } return; }

    This is ofcourse a terribly hack, you'd be a lot better of if you store your references somewhere where you can retrieve them easier.

    -- Joost downtime n. The period during which a system is error-free and immune from user input.
(jeffa) Re: Recovering References from Interpolation
by jeffa (Bishop) on Jun 10, 2002 at 14:29 UTC
Re: Recovering References from Interpolation
by vladb (Vicar) on Jun 10, 2002 at 14:29 UTC
    You ask,

    After such an interpolation happens - is the object the reference is/was pointing to destroyed if this was the last reference.

    In your particular code, the answer would be now as $ref variable that also stores the reference is still 'effective' or within the scope. However, if you had something like this:

    my $ref2; { # Block A my @aha = (1,2,3,4,5); my $ref = \@aha; $ref2="$ref"; } print "@$ref\n"; print ref($ref), " $ref\n"; print ref($ref2)," $ref2\n";
    I believe, the answer would be 'yes' when you are at a point in your code outside of 'Block A'.

    UPDATE: Regarding your second question (B), you could try using Devel::Pointer to fiddle around with your 'stringified' references and bring them back to 'life'. Try this code, for example (warning: I haven't tested this...):
    use Devel::Pointer; my @aha = (1,2,3,4,5); my $ref = \@aha; my $ref2 = "$ref"; my ($addr) = ($ref2 =~ m/\(\0\x(\d+)\)/); $real_ref = deref($addr); # $real_ref must now point to the @aha array..


    UPDATE 1: In addition to Devel::Pointer, there's this PeekPoke module that you might also find interesting. Basically, it allows you to peek a value stored at a given address. Of course, due to the nature of Perl variables (arrays specifically), I wouldn't advice this method for actually accessing individual array's elements. Unlike in C where each array's element could be easily accessed via a pointer (or address peek), Perl arrays is a bit more involved structure, and the address you get with \@array isn't pointing to the first array element but rather the beginning of the Perl structure representing the array. ..

    _____________________
    $"=q;grep;;$,=q"grep";for(`find . -name ".saves*~"`){s;$/;;;/(.*-(\d+) +-.*)$/; $_=["ps -e -o pid | "," $2 | "," -v "," "];`@$_`?{print"+ $1"}:{print" +- $1"}&&`rm $1`; print$\;}