in reply to Re-blessing || Re-constructing objects

Is a valid answer "never, and if I see code that re-blesses, I make sure it gets red flagged"? I didn't see that in your poll, but that's would I would check off.

-- Randal L. Schwartz, Perl hacker
Be sure to read my standard disclaimer if this is a reply.

  • Comment on Re: Re-blessing || Re-constructing objects

Replies are listed 'Best First'.
Re^2: Re-blessing || Re-constructing objects
by Juerd (Abbot) on Apr 17, 2006 at 22:38 UTC

    Is a valid answer "never, and if I see code that re-blesses, I make sure it gets red flagged"? I didn't see that in your poll, but that's would I would check off.

    Re-blessing can be very useful way to inactivate destroy your object while it hasn't been destroyed. Imagine, for example, DBI's database connection handles. For this contrived case, assume that connections never die except by explicit connection from your own side. After $dbh->disconnect, they're mostly useless. If they were blessed into another class, and already cleaned up internally, a check for connection at the beginning of each method is no longer needed. Great for performance, great for keeping your code clean. And the clean code would inspire me to add better diagnostics: instead of just "prepare on an inactive database handle", you could add "(inactive because of ->disconnect in foo.pl line 15)". Possible without reblessing, but not as nice.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      Some of this flew right over/around my head, but your point seems to be avoiding a call to DESTROY for the original class- so you re-bless them into a class whose purpose it is to recycle the object, then discard of it appropriately. Is this the same as subclassing it to override the DESTROY method, or is there extra niftiness that I'm missing?

      Writing such a class would require co-maintaining it with the parent class if you break encapsulation (as merlyn points out) but if that's not a problem, sounds good. I am interested in seeing a less contrived example of what you suggest.

      "One is enough. If you are acquainted with the principle, what do you care for the myriad instances and applications?"
      - Henry David Thoreau, Walden

        Some of this flew right over/around my head, but your point seems to be avoiding a call to DESTROY for the original class- so you re-bless them into a class whose purpose it is to recycle the object, then discard of it appropriately. Is this the same as subclassing it to override the DESTROY method, or is there extra niftiness that I'm missing?

        I use this technique to bridge the time in between inactivation and actual destruction: the object is no longer usable (possibly only partly), but there are still references to it, so it hasn't been destroyed yet. If some state (e.g. connected or disconnected) is so important for how an object works, I think it makes sense to not store the state as a property, but by changing the class. It certainly makes programming easier.

        There are good reasons to want to inactivate an object before destruction. If you let lexical destruction handle it, you may accidentally keep your heavy active state (connection) until global destruction, which may take hours, days, or even weeks before it happens. Also, if inactivation is just a side-effect of destruction, you can't easily handle things like an ENOSPC in a close. However, when the object is no longer active, you want to be sure that using it properly fails (throws an exception). You could do this by checking the state at the beginning of each method call, but I think it's easier and makes more sense to change the class, and generate methods that croak there.

        Recycling objects doesn't work just by reblessing it. You could, however, recycle objects that you have wrapped. But you can do that in a DESTROY method too, so it's not a reblessing specific game. If you want to re-use your $self later, you can use Data::Swap to swap($self, $foo) (where $foo is blessed into the inactive state class), and then store $foo (which after the swap is what $self was before) for re-use.

        Writing such a class would require co-maintaining it with the parent class if you break encapsulation (as merlyn points out) but if that's not a problem, sounds good.

        Every line of code you write has to maintained. Reblessing can result in having fewer lines to maintain, but it can also result in having to maintain a little more. If you properly inherit methods that work in both/all states, then you don't have code duplication and isa works as expected. I'd generate the methods that croak in a foreach loop, instead of repeating the same code. And, of course, you don't have to break encapsulation. When you do, it may or may not be okay, depending on how you broke it and what part you broke.

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re^2: Re-blessing || Re-constructing objects
by blogical (Pilgrim) on Apr 17, 2006 at 21:27 UTC
    It certainly is. It would be even more useful to hear why. *nudge nudge*

    "One is enough. If you are acquainted with the principle, what do you care for the myriad instances and applications?"
    - Henry David Thoreau, Walden

      Why not re-bless? For one thing, it causes very tight coupling. You can't re-bless a class and expect it to still work if you don't know exactly how it's implemented, and you aren't supposed to care about that. It kills your abstraction.

        But what if the the classes are intentionally written and maintained with this in mind? Users don't even need to peek inside when the action is supported through methods. Maintaining sibling subclasses that rely on the same parent doesn't seem abusive or even unusual.

        An example of my own use is dealing with user instances. Prior to validation, users interact with the system via an instance of the anon_user class. Should they log in, their instance is elevated into one of the user classes (depending on their status). The effects of some methods will change, and additional data might get grafted on. But I also want all the information I've already collected when I go to create their validated user object, and lo, there it is behind the anon_user veil, ready and waiting. Sometimes they go through a cascade of changes in user-type. What would be the object-appropriate way for me to go from one state to the next in such a situation?

        I can agree with you that it doesn't make sense to grab a random data structure ("how it's implemented") and start abusing it. The author should have the freedom to make any changes they want under the hood. But when you are the author, such preservation and re-use of data structures seems prudent if applicable.

        "One is enough. If you are acquainted with the principle, what do you care for the myriad instances and applications?"
        - Henry David Thoreau, Walden