1

Is unblessing Perl objects means having a dreadful design ?
If yes, can any one explain this to me ?
BTW, Here's the discussion which fired this question, check comments on the question

Community
  • 1
  • 1
Ashraf Bashir
  • 9,686
  • 15
  • 57
  • 82
  • I can't imagine why you would want to do this. As the OP of the original question, presumably you have a scenario in mind? If so then it would be useful if you explained it – Borodin Aug 15 '15 at 20:36
  • @Borodin, I opened this question in a separate thread to avoid XYProblem. I need to understand from design perspective why it should be avoided (Should it?). Not asking about a specific scenario. I need to know in general why should I avoid its usage ? i.e. performance issue ? or design issue ? or another thing which I am missing ? ... etc. It would be great if you may elaborate more on this topic in responses. Thanks :) – Ashraf Bashir Aug 15 '15 at 20:39
  • 3
    @AshrafBashir Design issue, because the language doesn't even support it (using C code to mess with the interpreter's data structures doesn't count). – melpomene Aug 15 '15 at 20:47

4 Answers4

4

Needing unbless certainly raises eyebrows. Since you can still use the object as the original data structure, it's almost never needed.

Modules that are picky about receiving unblessed hash references vs objects tend to have options to not be so picky, for example allow_blessed and convert_blessed in JSON.

Joni
  • 108,737
  • 14
  • 143
  • 193
4

One application is an object implemented as a hash reference and you also wish to overload the %{} dereferencing operator [EDIT: and you also want to support perls older than v5.10.1 -- otherwise you should just use no overloading.]

package Foo;
use overload '+' => sub { $_[0]->get + $_[1] },
             ...,
             '%{}' => sub { return { foo => "bar", this => $_[0] } },
             ...;

Now for any $foo that has type Foo, trying to access an element like $foo->{$key} will invoke your overloaded %{} method, and your access will fail.

The workaround is to change your object's type temporarily while you access your object's member, and change it back when you are done. You could do this by unblessing your object, but it is more often done (and more easily done) by blessing it to a garbage value.

sub Foo::bar {   # access 'bar' member of Foo object
  my $self = shift;
  # $self->{bar} will invoke Foo::{'%{}'}, and we don't wan't that

  my $ref = ref $self;
  unbless($self);    #   or  bless $self, 'Not::An::Object::Name'
  # now $self->{bar} is accessible

  my $value = $self->{bar};
  bless $self, $ref;        # restore object type
  return $value;
}

Another example is given in the section on "Two-face-References" in overload


I use this pattern here, for another example.

mob
  • 117,087
  • 18
  • 149
  • 283
  • I'd be very, very careful with that. If you execute any code between `unbless` and re-`bless`, there's a chance it will explode and never reach `bless` again, permanently "sabotaging" your object. – melpomene Aug 16 '15 at 10:31
  • 2
    Why not use `no overloading '%{}'; return $self->{bar}` instead of monkey around with bless/unbless? [overloading](https://metacpan.org/pod/overloading). – chansen Aug 16 '15 at 12:47
  • @mob, yes you are right! I said `no overloading`, not `no overload`, read the documentation for [overloading](https://metacpan.org/pod/overloading)! – chansen Aug 16 '15 at 21:02
  • Thanks @charsen, didn't know about `overloading`. It has been available since v5.10.1. – mob Aug 17 '15 at 12:59
1

This is an idle and silly question. You have no purpose in mind for unbless but have chosen it at random from an obscure CPAN module to ask why it reflects bad design. You may as well ask how to undeclare a variable that has been declared with my. That is also quite possible in XS code, but I hope it's clearly rather stupid?

The issue I have with unbless is that you have created a data structure -- anything from a scalar variable or a file handle to a nested hash or array -- and called bless so that Perl know how to resolve method calls on that object

So now you want to unbless it. That will leave the data intact, and the main difference will be that any method calls will now result in a fatal error

Can't call method ... on unblessed reference

So what was your unbless for? If you're relying on Perl to give you this fatal error then it's just as easy to assign undef to the object which gives rise to this fatal error instead

Can't call method ... on an undefined value

but has the advantage that your data structure may be destroyed so that the memory is released

If you want something more solid then, because references may be passed to multiple sections of code, unbless would be an example of action at a distance which is discredited by many more people than myself

Borodin
  • 126,100
  • 9
  • 70
  • 144
  • 2
    "assign `undef` to the object" is nonsense. You can't assign `undef` to a hash or array, only to a scalar. And even then it won't affect method calls, because having an object that is a scalar contain `undef` is perfectly fine. – melpomene Aug 15 '15 at 21:02
  • @melpomene: As you know, a Perl object is always a *reference to blessed data*. There is no way to call an object's method without a reference, so I think it is clear that what I meant was to assign `undef` to the scalar variable holding the reference – Borodin Aug 15 '15 at 21:07
  • 2
    I'd say an object is the blessed data. `bless \%foo; (\%foo)->bar()` works fine. You can't assign `undef` because there's no "the scalar variable" there. Even in a more conventional setting, you normally have many different variables storing a reference to the object (several of them called `$self` if you're currently in a method call of that object). :-) – melpomene Aug 15 '15 at 21:10
  • 2
    @melpomene: You may well say that, but I think you'd be different from the crowd. I am sure you don't think `(\%foo)->bar` is a common construction, and I am also sure you know what I mean by *"assign `undef` to the object "* – Borodin Aug 15 '15 at 21:21
  • 2
    "I am also sure you know what I mean by *"assign undef to the object "*" - no, I don't. If an "object" is the blessed thing, it's not a scalar; if an "object" is a reference to a blessed thing, there is no "*the* object" because there can be 0 or more of it. – melpomene Aug 15 '15 at 21:24
  • 1
    @melpomene: In a Perl world where `my $object = Class->new` makes sense, so does `$object = undef`. I don't believe you're as naïve as you pretend – Borodin Aug 15 '15 at 21:40
  • 3
    Re "If you're relying on Perl to give you this fatal error then it's just as easy to assign undef to the object which gives rise to this fatal error instead" No, that's not true. `perl -MData::Structure::Util=unbless -e'sub m { } $o1 = $o2 = $o = bless({}); undef($o1); $o->m; unbless($o2); $o->m;'` – ikegami Aug 15 '15 at 22:35
  • @ikegami: So can I put you down as recommending `unbless` as a useful design construct? – Borodin Aug 15 '15 at 23:13
  • @Borodin, No, I think unblessing and reblessing are awful practices. – ikegami Aug 15 '15 at 23:17
  • 2
    @Borodin Sure, `$object = undef` makes sense and I never argued against that. I'm saying `$object` is not *the* object (singular and unique) because the same reference may be stored in dozens of other places (making them all objects, too). I don't believe you're as naïve as you pretend. – melpomene Aug 16 '15 at 10:28
-1

I think unbless is useful when I want to store the object data, but not the object data with class name; precisely, when the nature of your object data meant to be production data, rather than for object self reference to work.

package My::Pkg;
use Storable qw/dclone/;
use Data::Structure::Util qw/unbless/;

sub _distribute_private_attr { 
 $_[0]->{_private_attrs} = {...}
}

sub new {
 my $obj = bless { Foo => [qw/bar/] };
 $obj->_distribute_private_attr();
 return $obj;
}

sub load {
 my $cls = shift;
 my $data = retrieve $_[0];
 my $obj = bless $data, $cls;
  $obj->_distribute_private_attr();
 return $obj
}

sub save {
 my $obj = shift;
 my $data = unbless ( dclone $obj );
 delete $data->{_private_attrs};
 store $data, $_[0];
}
1;

package main;
use Some::Other::Mod;

my $obj = My::Pkg -> new;
$obj->{Bar} = "Baz";
$obj->save ("someFile");

my $obj2 = My::Pkg->load("someFile"); # Now we can do this
my $obj3 = Some::Other::Mod->load("someFile"); # or this
my $data = retrieve "someFile"; # or this

And now, the data structure stored can be used by others without messing with other class thing, yet nothing has messed with the runtime instance .

Panda
  • 73
  • 1
  • 6
  • 1
    In your `$obj` example, once you have the object, don't mess with the internals. I'd do this another way. I'd have a `as_hash` method that returns the keys and values that are public (dcloned). Then, save that, or do whatever. It would be very weird for one class to use exactly the same data structure as a completely different class, and to depend on one of those classes writing it to disk in a certain way. – brian d foy Aug 02 '23 at 20:57
  • @briandfoy May I know your point regarding "mess with the internals"? and how "weird" is that different classes accessing same data structure? For example, a `Calendar Class` and `TodoList Clas`s both accessing a TodoList data structure, and they both also accessing a Note data structure that provided by `Notes Class`. Is that sound weird to you? – Panda Aug 25 '23 at 03:35
  • If you want to do OO programming, stick the the interface of the object (or write a better interface). Along with that, if two different objects are going to change the same data, you likely have the wrong interface. They are either so similar they should not be two class, or so different that their changes would disrupt the other class, – brian d foy Aug 25 '23 at 08:33