Re: Re-blessing || Re-constructing objects
by demerphq (Chancellor) on Apr 18, 2006 at 10:02 UTC
|
Ive found reblessing can be useful in a couple of circumstances. One is when dealing with stuff like delayed loading. For instance if you have an object that has a "lite" and a "heavy" representation and the transition from lite to heavy is expensive it can be useful to have the object metamorphize itself from the lite to heavy on demand.
You could do the same thing with an internal if() but then you are duplicating method dispatch in an inefficient way in that you are adding an if() that shouldnt be there.
Another, related use of reblessing is for the purpose of "freezing" an object in a serialization tool. You may have an object that simply cant be represented conveniently in one form, so you define a secondary class with an "unfreeze" method for the purpose. With AUTOLOAD the frozen class can unfreeze itself on demand by converting itself and reblessing when a method is called on it.
As perrin points out elsewhere both of these mean you have tight coupling between the classes, but for these type of purpose thats pretty much a given. I see this in a sense as a specialized form of a factory. And in an object/class factory you also have tight coupling.
A last use for reblessing that I've used is as an attribute on privately created references without using method dispatch on the blessed objects. In that case I see nothing wrong with it at all. It can be convenient at times to use bless as a way to attach an attribute to an arbitrary reference without changing the contents of that reference. Of course you can also add insideout objects but that can be more hassle. It basically depends on which side of the abstraction layer its on, if its totally private to your code i dont see the problem, if it "leaks" past your codes abstraction layer then it probably is a problem.
All of this is for specialized stuff where IMO the normal rules dont necessarily apply. But as a general rule using rebless gratuitiously is IMO unwise
---
$world=~s/war/peace/g
| [reply] |
Re: Re-blessing || Re-constructing objects
by dragonchild (Archbishop) on Apr 18, 2006 at 00:11 UTC
|
Nearly every reason to rebless (including salva's example of Class:StateMachine) are better served with facades, especially as inside-out. For example:
package Facade::Base;
sub new {
my $class = shift;
my ($main) = @_;
return bless \$main, $class;
}
package Facade::One;
use base 'Facade::Base';
sub example {
my $self = shift;
# foo() is a method on the object I expect to facade over
$$self->foo( @args );
}
package main;
my $datastructure = Main::Class->new( %params );
my $facade1 = Facade::One->new( $datastructure );
# Now, I can call Facade::One's methods on $facade1.
# I can also change the facade by doing something like:
my $facade2 = Facade::Two->new( $$facade1 );
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] [d/l] |
|
|
Interesting. I hadn't heard of facade patterns (unsurprisingly) but the concept is simple enough. I would still be interested in an explanation of why facades are better, as I am new to them and perhaps can't fully grok the beauty of your example.
"One is enough. If you are acquainted with the principle, what do you care for the myriad instances and applications?" - Henry David Thoreau, Walden
| [reply] |
|
|
I can't see why this facade aproach is a better solution other than because it doesn't rebless objects.
In Perl 5, blessing is just a way to attach a dispatch table to some data structure. If I want my data structure to behave differently at different points in time the obvious solution is to change its dispatch table accordingly, so reblessing it.
| [reply] |
|
|
I suppose you could say that all OO is just a way to attach a dispatch table to some data structure. However, the other classes are not supposed to need to know what the actual data structure is, since they access it through methods. If you re-bless an object, your code (the part that does the re-blessing and the class you re-bless it into) will now break if the internals of the original class break, even if the API doesn't change.
| [reply] |
|
|
|
|
|
|
|
|
|
To paraphrase perrin, all I have to do is depend on the public (i.e., documented) API. I don't have to depend on how the object is implemented.
I think the disconnect between how you're looking at things and how I am looking at things is I see OO as a set of behaviors that, when necessary, has some data to support those behaviors. You're looking at it as a data structure that may or may not have some behaviors associated with it. That's a pretty big disconnect.
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
Re: Re-blessing || Re-constructing objects
by merlyn (Sage) on Apr 17, 2006 at 21:24 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.
| [reply] |
|
|
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.
| [reply] |
|
|
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
| [reply] |
|
|
|
|
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
| [reply] |
|
|
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.
| [reply] |
|
|
|
|
|
|
|
|
Re: Re-blessing || Re-constructing objects
by salva (Canon) on Apr 17, 2006 at 21:52 UTC
|
- Implementing a state machine (Class::StateMachine).
- Objects for which only partial information is available at construction time (for instance, when it's comming through the network). You can init an object in a common base class and once more information is available rebless it into a more specific one.
| [reply] |
|
|
A reflection of state seems to be the underlying factor between these- either in a state defined by known information, or in a state that indicates that there are known unknowns. Using class change to reflect state change (same structure, different situation due to state). Thanks!
"One is enough. If you are acquainted with the principle, what do you care for the myriad instances and applications?" - Henry David Thoreau, Walden
| [reply] |
Re: Re-blessing || Re-constructing objects
by xdg (Monsignor) on Apr 18, 2006 at 14:00 UTC
|
Reblessing is one approach for doing foreign inheritance in inside-out objects without using a facade. For example, what if you want to keep additional state with a filehandle object? The following code is adapted from File::Marker:
package File::With::State;
use strict;
use warnings;
use Scalar::Util qw( refaddr );
use base 'IO::File';
my %stash; # hold inside-out state
sub new {
my $class = shift;
# create the object and rebless
my $self = IO::File->new();
bless $self, $class;
# initialize the object
$stash{ refaddr $self } = {};
$self->open( @_ ) if @_;
return $self;
}
sub stash {
my ($self, $key, $value) = @_;
return unless $key;
$stash{ refaddr $self }{ $key } = $value if $value;
return $stash{ refaddr $self }{ $key };
}
# Note: this simple example is not thread-safe and also
# needs a destructor to avoid leaking memory
The advantage of this over the facade pattern is that you can use the object directly wherever you would use a filehandle.
my $fh = File::With::State->new( 'some_file' );
my @lines = <$fh>;
$fh->stash( line_count => scalar @lines );
I think this use of reblessing is "safe" because it reblesses into a subclass, which means that all the methods of the original class are available (although they could be overridden as usual with subclassing). No functionality is lost through the reblessing.
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
| [reply] [d/l] [select] |
Re: Re-blessing objects
by adrianh (Chancellor) on Apr 18, 2006 at 07:39 UTC
|
| [reply] |
Re: Re-blessing objects
by jdporter (Paladin) on Apr 17, 2006 at 20:36 UTC
|
Re-blessing doesn't do #2.
We're building the house of the future together.
| [reply] |
|
|
| [reply] |