Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^2: Avoiding circular references

by frazap (Monk)
on Dec 06, 2019 at 13:54 UTC ( [id://11109749]=note: print w/replies, xml ) Need Help??


in reply to Re: Avoiding circular references
in thread Avoiding circular references

I would have someting like this working
use strict; use warnings; use Devel::Cycle; package A; sub new { my ( $class, $href ) = @_; my $self = { dbi => $$href{dbi} }; $self->{helper} = Helper->new( helper_function => sub { my $dbi = $$href{dbi}; return $self->this_is_from_A(@_); } ); bless $self, $class; } sub do_something { my $self = shift; $self->{helper}->called_from_helper(); } sub this_is_from_A { my ($self, $arg) = @_; print "$arg\nthis_is_from_A using $dbi\n"; } package Helper; sub new { my $class = shift; my %def = ( a => "something"); my %arg = ( ref $_[0] eq "HASH" ? ( %def, %{ $_[0] } ) : ( %def, + @_ ) ); my $self = \%arg; bless $self, $class; } sub called_from_helper { my $self = shift; print "called_from_helper\n"; my $coderef = $self->{helper_function}->(); $coderef->("param from Helper"); } package main; my $a = A->new( { dbi => "some dbi object" } ); $a->do_something(); $a->do_something(); find_cycle($a);
But this does not even compile since $dbi in this_is_from_A is not declared.

Replies are listed 'Best First'.
Re^3: Avoiding circular references
by tobyink (Canon) on Dec 06, 2019 at 14:48 UTC

    So you pass $dbi as an argument.

    package A; sub new { my ( $class, $href ) = @_; my $self = { dbi => $$href{dbi} }; $self->{helper} = Helper->new( helper_function => sub { my $dbi = $$href{dbi}; return $self->this_is_from_A($dbi, @_); # p +ass $dbi } ); bless $self, $class; } sub do_something { my $self = shift; $self->{helper}->called_from_helper(); } sub this_is_from_A { my ($self, $dbi, $arg) = @_; # r +eceive $dbi print "$arg\nthis_is_from_A using $dbi\n"; }

      Thanks !

      but that still make a circular reference because of $self

      This works

      use strict; use warnings; use Devel::Cycle; package A; sub new { my ( $class, $href ) = @_; my $self = { dbi => $$href{dbi} }; $self->{helper} = Helper->new( helper_function => sub { &this_is_from_A( $$href{dbi}, @_) } ); bless $self, $class; } sub do_something { my $self = shift; $self->{helper}->called_from_helper(); } sub this_is_from_A { my ($dbi, $arg) = @_; print "$arg\nthis_is_from_A using $dbi\n"; } package Helper; sub new { my $class = shift; my %def = ( a => "something"); my %arg = ( ref $_[0] eq "HASH" ? ( %def, %{ $_[0] } ) : ( %def, + @_ ) ); my $self = \%arg; bless $self, $class; } sub called_from_helper { my $self = shift; print "called_from_helper\n"; $self->{helper_function}->("param from Helper"); } package main; my $a = A->new( { dbi => "some dbi object" } ); $a->do_something(); $a->do_something(); find_cycle($a);
        but that still make a circular reference because of $self

        You could stick close to your original solution with a method call if you pass a weakened copy of $self to the subroutine reference:

        use strict; use warnings; use Devel::Cycle; package A; use Scalar::Util qw/weaken/; sub new { my ( $class, $href ) = @_; my $self = { dbi => $$href{dbi} }; my $weak_self = $self; weaken $weak_self; $self->{helper} = Helper->new( helper_function => sub { $weak_self->this_is_from +_A(@_) } ); bless $self, $class; } # ....the rest remains unchanged.
        That way, this_is_from_A has full access to the $self object (which isn't needed in your example so far).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11109749]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2024-03-29 11:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found