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

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

Hello,

With the risk of asking a stupid question, I wonder if it is possible to (locally?) replace an object in Perl.

Bellow is a simple code which illustrates my question.

use 5.014; package OldObj { sub new {bless {}, __PACKAGE__} sub test { print "You're still using the old object!\n"; } }; package NewObj { sub new {bless {}, __PACKAGE__} sub test { print "Yuppie! This is the new object!\n"; } }; my $keep = OldObj->new(); # object_1 my $change = OldObj->new(); # object_2 my $ref1 = $change; # points to object_2 my $ref2 = $ref1; # points to object_2 # object_2 needs to be replaced with another object, # but the object_1 should still be ref 'OldObj' # ... code needs to be added here ... say ref($ref1); # should print 'NewObj' $ref2->test(); # should go to NewObj::test() $keep->test(); # should go to OldObj::test()

What is the magic formula for doing this? Thanks

Replies are listed 'Best First'.
Re: Replacing objects
by kennethk (Abbot) on Dec 18, 2013 at 19:27 UTC
    Assuming I follow, what you need to do is bless the object into your new package. Since you seem to want to maintain all your previous referencial linking, you cannot change the underlying hash reference. Do you get your desired result with:
    use 5.014; package OldObj { sub new {bless {}, __PACKAGE__} sub test { print "You're still using the old object!\n"; } }; package NewObj { sub new {bless {}, __PACKAGE__} sub test { print "Yuppie! This is the new object!\n"; } }; my $keep = OldObj->new(); # object_1 my $change = OldObj->new(); # object_2 my $ref1 = $change; # points to object_2 my $ref2 = $ref1; # points to object_2 # object_2 needs to be replaced with another object, # but the object_1 should still be ref 'OldObj' # ... code was added here ... bless $change, 'NewObj'; say ref($ref1); # should print 'NewObj' $ref2->test(); # should go to NewObj::test() $keep->test(); # should go to OldObj::test()
    I could see this evolving into a maintenance headache, but that's a broader question.

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      Wow, that simple? And I was thinking about copying, aliasing and stuff.
      
      Thank you very much. This solves my problem.
Re: Replacing objects
by dcmertens (Scribe) on Dec 18, 2013 at 19:27 UTC

    You're looking for the bless operator/command/function/whatever it's called:

    bless $change, 'NewObj';

    The ability to change an object's class at runtime is pretty powerful and can be used for mock objets, for example. However, you should only do this if you are sure that the internal storage is compatible.

      ... you should only do this if you are sure that the internal storage is compatible.

      As an illustration of this important point, consider:

      >perl -wMstrict -le "use 5.014; ;; package Foo { sub new { return bless { fooble => 'wonkem' }; } sub mungeit { my $self = shift; my ($m) = @_; return $self->{fooble} .= $m; } } ;; package Bar { sub new { return bless { fooble => 1729 }; } sub mungeit { my $self = shift; my ($m) = @_; return $self->{fooble} += $m; } } ;; my $foo_obj = Foo->new; my $bar_obj = Bar->new; ;; print $foo_obj->mungeit('zoot'); print $bar_obj->mungeit(42); ;; bless $foo_obj, 'Bar'; ;; print $foo_obj->mungeit('zonk'); " wonkemzoot 1771 Argument "zonk" isn't numeric in addition (+) at -e line 1. Argument "wonkemzoot" isn't numeric in addition (+) at -e line 1. 0

      trizen: In fact, the whole business of re-bless-ing an object into another class is highly suspicious. Is this an instance of an XY Problem? What are you really trying to do?

Re: Replacing objects
by sundialsvc4 (Abbot) on Dec 19, 2013 at 00:39 UTC

    The superficial answer, to your immediate question, is (of course) “yes.”

    By that I mean:   the bless() primitive (simply...) associates a particular class/object definition with a particular object-instance, such that the runtime interpreter, when presented with a “method-call,” will use that particular association in its effort to resolve the call.   Therefore, “yes... it is technically possible to, on-the-fly, change that association, just by calling bless() again.”

    But, now, the “XY Problem” Question ...   What, exactly, are you trying to accomplish here?   (Hey, haven’t we a-l-l been in this very spot?)   A thing that “technically speaking, the interpreter ‘allows” you to do,” might or might not be the best ‘There’s More Than One Way To™’ way to do it, but “by now, we’re just too damm close to it.”   Therefore, please tell us more about your ultimate goal, so that The Peanut Gallery might assist you in assessing whether the Tree that you are currently barking up, really is the right Tree.   Perhaps there is another, better, “way to do it.”   :-)