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

For example, if I have a simple hashref-based object, and I want to turn it into a unblessed hash (the same hash, not a copy of it), is there any way to do that?

I know that I can easily copy it into an unblessed hash like this:

package HashBasedObject; sub new { my ($class, %arg) = @_; bless {%arg}, $class; } sub unblessed_copy { my $self = shift; return {%$self}; } 1;
or an an arrayref based object like this:
package ArrayBasedObject; sub new { my ($class, @arg) = @_; bless [@arg], $class; } sub unblessed_copy { my $self = shift; return [@$self]; } 1;
but is there a way to unbless $self directly.

Replies are listed 'Best First'.
Re: How can I unbless an object?
by chromatic (Archbishop) on Jul 19, 2002 at 18:01 UTC

    The idea of a 'curse' operator has been discussed on p5p from time to time. I seem to recall it's fallen afoul of rule #1, however. Larry doesn't like it.

    Out of curiosity, what use do you see for such a feature?

      It's never occured to me untill now, but i can definitely think of some cases where you may have blessed a refrence for use in some code (ie: doing OO) but when passing the ref to other code which drives it's behavior by the ref type of it's arg, you may want it to be treated as the underlying hash that it is.

      I don't know if "curse" is really the right term for the case I'm thinking of (where you don't want to change the ref itself, you just wan a new ref to the same object with a different type ... which strikes me as being almost like a "cast" method...

      my $foo = new Foo; my $hash = cast 'HASH', $foo; print ref $hash; # 'HASH'
        but i can definitely think of some cases where you may have blessed a refrence for use in some code (ie: doing OO) but when passing the ref to other code which drives it's behavior by the ref type of it's arg, you may want it to be treated as the underlying hash that it is.
        And all I can think of when I think of that is "bad design".

        -- Randal L. Schwartz, Perl hacker

        use Scalar::Util qw(reftype);

        using reftype instead of ref allows hash checking of an object from any class

      The intended use is to unbless deeply nested objects for use with Template Toolkit (TT2) so I can add/modify/remove fields in the hash before template processing.

      If you pass TT2 an object that is a hash and tell it to access object.element_name, it will return

      $object->element_name

      if that method exists rather than

      $object->{element_name}.

      If I could unbless the object, then I could force it to use the latter. There are other workarounds, but if "unbless" existed in some form, it might be simpler.

        Ahh, yes. Since I'm so enamoured with Template, it's hard to scream "too much DWIMmery" there. But in this sense, yes, there's a mismatch between that DWIMish design, and what you actually want to hand to it.

        Do you really need two-way communication? Can you not just hand it a copy?

        If you do need two-way communication, perhaps you could hand it a tie'd hash reference, and then map that back to your object.

        -- Randal L. Schwartz, Perl hacker

        I think you are overly worried about the overhead of method calls. However, if you really want do this I recommend implementing a method on the object that returns an unblessed version of itself appropriate for use with TT. This gives you an opportunity to later do some extra magic in this method, like rearranging the data to make for a simpler template.
        In answer to my own question, I just discovered a recent CPAN module that can unbless an object. See Data::Structure::Util.
Re: How can I unbless an object?
by vladb (Vicar) on Jul 19, 2002 at 18:07 UTC
    But isn't this already as simple as you could get? Here's the code I've played with:
    use Data::Dumper; my $bhash = bless { key1 => 'val1', key2 => 'val2' }, 'FOO'; my %uhash = %$bhash; print Dumper($bhash); print Dumper(\%uhash); print "done\n";
    And the output is:
    $VAR1 = bless( { 'key1' => 'val1', 'key2' => 'val2' }, 'FOO' ); $VAR1 = { 'key1' => 'val1', 'key2' => 'val2' }; done
    The bless() is used to associate the object a reference points to with a package that defines the object class. I am frankly not aware of any operator in Perl for 'curse' or 'unbless'.

    Update: mp when you use the bless() operator on a hashref like so:
    my %ahash = ( key1 => 1, key2 => 2 ); bless \%ahash, 'FOO';
    You end up 'labeling' or 'associating' the %ahash structure with the package 'FOO'. Here's the code to prove this:
    use Devel::Peek 'Dump'; use Data::Dumper; my %ahash = ( key1 => 'val1', key2 => 'val2' ); print "ORIGINAL HASH:\n"; print Dumper(\%ahash) ."\n"; print Dump(\%ahash) ."\n\n"; my $bhash = bless \%ahash, 'FOO'; print "ORIGINAL HASH (after blessing, note it's now been associated wi +th the 'FOO' package!!):\n"; print Dumper(\%ahash) ."\n"; print Dump(\%ahash) ."\n\n";
    Which when you run it produces this output:
    ORIGINAL HASH: $VAR1 = { 'key1' => 'val1', 'key2' => 'val2' }; SV = RV(0x3b828) at 0x2307c REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x2dbc4 SV = PVHV(0x8ea80) at 0x2dbc4 REFCNT = 2 FLAGS = (PADBUSY,PADMY,SHAREKEYS) IV = 2 NV = 0 ARRAY = 0x25160 (0:6, 1:2) hash quality = 150.0% KEYS = 2 FILL = 2 MAX = 7 RITER = -1 EITER = 0x0 Elt "key1" HASH = 0x3e4d49 SV = PV(0x23444) at 0x2316c REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x952b8 "val1"\0 CUR = 4 LEN = 5 Elt "key2" HASH = 0x3e4d4a SV = PV(0x2342c) at 0x23250 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x952e8 "val2"\0 CUR = 4 LEN = 5 ORIGINAL HASH (after blessing, note it's now been associated with the +'FOO' package!!): $VAR1 = bless( { 'key1' => 'val1', 'key2' => 'val2' }, 'FOO' ); SV = RV(0x3b828) at 0x2307c REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x2dbc4 SV = PVHV(0x8ea80) at 0x2dbc4 REFCNT = 3 FLAGS = (PADBUSY,PADMY,OBJECT,SHAREKEYS) IV = 2 NV = 0 STASH = 0x59b1c "FOO" ARRAY = 0x25160 (0:6, 1:2) hash quality = 150.0% KEYS = 2 FILL = 2 MAX = 7 RITER = -1 EITER = 0x0 Elt "key1" HASH = 0x3e4d49 SV = PV(0x23444) at 0x2316c REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x952b8 "val1"\0 CUR = 4 LEN = 5 Elt "key2" HASH = 0x3e4d4a SV = PV(0x2342c) at 0x23250 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x952e8 "val2"\0 CUR = 4 LEN = 5
    Note that soon after the call to the 'bless' operator, the original hash structure was altered. There's now been a new 'STASH' field added to the hash RV structure. Again, as far as I know there's no means in current version of Perl to simply yank that field from the underlying hash structure. I'll play some more with this to see if there's a way of obtaining an unblessed structure without unnecessary copying however.

    _____________________
    # Under Construction
      What you suggest works and is basically what I'm currently doing, but I would prefer not to have to waste resources to copy the hash just to get a non-blessed copy of it, especially when the particular application of this can end up making a copy of some fairly large hash of array of hash of ... - type structures.

      Update: changed wording slightly.

        Please see my updated post above.

        Also, looking at your particular application of this, I can't quite understand why do you need to worry much about blessed entities (structures). No matter what 'class' name your hash structure has been branded with, in the end you still deal with the same hash structure. The $self variable is simply referencing that 'named' structure. And when you do $self->method(), Perl simply interprets it as FOO::method($self) on the basis that '$self' has been 'labeled' as belonging to the package or being of type 'FOO'. That's all. Nontheless, I can still do this:
        package FOO; sub new { bless { key1 => 1, key2 => 2 }; } package main; my $foo = new FOO(); print "Look, first key = '$foo->{key1}'!\n";
        Output:
        Look, first key = '1'!
        Clearly, that $foo object is nothing but a reference to a hash. Simple as that.

        _____________________
        # Under Construction