in reply to Re: Is there an advantage to storing references to objects in an attribute instead of the object itself?
in thread Is there an advantage to storing references to objects in an attribute instead of the object itself?

OK, I ran your code. Very interesting. Thanks for illustrating this problem for me so clearly. Circular references are one of those concepts I blew off and didn't worry about. It's probably time I started worrying.

So what's the best solution to my problem? Here's my self-contained code that illustrates what I'm doing:

#! /usr/bin/env perl use warnings; use strict; package BigObjs; use Moose; has 'little_objs' => ( is => 'rw', isa => 'HashRef', default => sub { +{} } ); # our reader method sub get_little_obj { my ($s, $id) = @_; return $s->little_objs->{$id}; } # add new little objects to our collection sub add_little_obj { my ($s, $little_obj) = @_; # create code ref to reader method in big object $little_obj->get_obj_by_id(sub{$s->get_little_obj(@_)}); $s->little_objs->{$little_obj->id} = $little_obj; } package LittleObjs; use Moose; has 'id' => (is => 'rw'); has 'data' => (is => 'rw'); has 'get_obj_by_id' => (is => 'rw'); sub alter_another_little_object { my ($s, $id) = @_; my $other_little_object = $s->get_obj_by_id->($id); $other_little_object->do_stuff; } sub do_stuff { my $s = shift; print "I'm doing stuff to: " . $s->id . "\n"; } no Moose; my $big = BigObjs->new(); my $little1 = LittleObjs->new(id => 'little1', data => 'foo'); my $little2 = LittleObjs->new(id => 'little2', data => 'bar'); $big->add_little_obj($little1); $big->add_little_obj($little2); $little1->alter_another_little_object('little2');

So you are saying I need to use sub{$s->get_little_obj(@_)} as an argument to a weaken function?

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest";
$nysus = $PM . ' ' . $MCF;
Click here if you love Perl Monks

  • Comment on Re^2: Is there an advantage to storing references to objects in an attribute instead of the object itself?
  • Select or Download Code

Replies are listed 'Best First'.
Re^3: Is there an advantage to storing references to objects in an attribute instead of the object itself?
by haukex (Archbishop) on Dec 03, 2017 at 11:22 UTC

    To reply to your various posts in this thread in one place:

    Circular references are one of those concepts I blew off and didn't worry about. It's probably time I started worrying.

    It's definitely something to keep in mind when building object trees like you are. I tried out some different ways to locate circular references in this node, but applying that to your code just shows a bunch of circular references of Class::MOP::* objects, so I'd guess Moose is wrapping everything up and hiding the actual circular references. Applying it to my code above shows them a little more clearly.

    I stored a reference to a reader method ... it provides encapsulation

    Personally, I don't think hiding the "big object" in a code ref adds much. Consider that the class for the big object should already provide all the necessary encapsulation, and so I think there's nothing wrong with simply providing a getter on the "little object" class that returns the big object. You might just consider making this field read-only.

    ... the weak_ref => 1 attribute property. However, slapping that in breaks my code.

    Yes, I can confirm that in your code putting weak_ref on either the little_objs or get_obj_by_id causes "Can't use an undefined value as a HASH/subroutine reference" errors. Also, if I take your code as shown here, and add a sub DESTROY to track destruction like I showed above, it shows the memory leak. Since adding a level of indirection with the code ref doesn't seem to break my code above, at the moment I'm guessing that it's the combination of Moose's weak_ref and the code ref that is causing the problem, but I haven't investigated this further, because I can fix the problem by doing what I said above, just giving the little object a reference to the big object:

Re^3: Is there an advantage to storing references to objects in an attribute instead of the object itself?
by choroba (Cardinal) on Dec 03, 2017 at 21:30 UTC
    I'd probably just store a weak reference to the big object directly in the little one, and use it in alter_another_little_object to get the other object:
    #! /usr/bin/perl use warnings; use strict; { package BigObjs; use Moose; has 'little_objs' => (is => 'rw', isa => 'HashRef', default => sub + { {} }); sub get_little_obj { my ($s, $id) = @_; return $s->little_objs->{$id}; } sub add_little_obj { my ($s, $little_obj) = @_; $little_obj->big_obj($s); $s->little_objs->{$little_obj->id} = $little_obj; } } { package LittleObjs; use Moose; has id => (is => 'rw'); has data => (is => 'rw'); has big_obj => (is => 'rw', weak_ref => 1); sub alter_another_little_object { my ($s, $id) = @_; my $other_little_object = $s->big_obj->get_little_obj($id); $other_little_object->do_stuff; } sub do_stuff { my $s = shift; print "I'm doing stuff to: " . $s->id . "\n"; } } my $big = BigObjs->new(); my $little1 = LittleObjs->new(id => 'little1', data => 'foo'); my $little2 = LittleObjs->new(id => 'little2', data => 'bar'); $big->add_little_obj($little1); $big->add_little_obj($little2); $little1->alter_another_little_object('little2'); warn "Done\n";
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re^3: Is there an advantage to storing references to objects in an attribute instead of the object itself?
by nysus (Parson) on Dec 02, 2017 at 23:13 UTC

    OK, so everything works if I put in the full object into the attribute with weak_ref in the attribute. Thanks so much! I greatly appreciate your consideration. Onward!

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest";
    $nysus = $PM . ' ' . $MCF;
    Click here if you love Perl Monks

Re^3: Is there an advantage to storing references to objects in an attribute instead of the object itself?
by nysus (Parson) on Dec 02, 2017 at 19:14 UTC

    OK, I see in Moose I have to use the weak_ref => 1 attribute property. However, slapping that in breaks my code. Hmm.

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest";
    $nysus = $PM . ' ' . $MCF;
    Click here if you love Perl Monks