Thenothing has asked for the wisdom of the Perl Monks concerning the following question:

Hi everyone I hope you're doing fine, first I want to say this is crosspost: https://stackoverflow.com/questions/77557869/central-constructor-share-data-bless-hash-between-packages

I will tried to explain better here and find a solution to this problem, and I hope to learn something new.

I want to have access the latest data of parent constructor in all childs packages in $self.

why I want to do this:

In the constructor, I call external packages so I assigned the result to the hash reference constructor, inside child package I need that data and others config values of parent.

Possible solution:

I found a solution with rebless, and with this code, but I need to create variable and I have to call $self->{data}->{key} I want to avoid that . I wish I can call just like this $self->{key} inside child package without rebless.

Here a full working example, but have to call $self->{data}->{key}:

package Father; my $store_data = { }; sub new { my $class = shift; return bless { data => $store_data }, $class; } 1; package Daughter; use parent qw(Father); sub status { my $self = shift; $self->{data}->{news} = 'bad'; return $self; } sub other { my $self = shift; return $self; } 1; package Son; use parent qw(Father); sub set { my $self = shift; $self->{data}->{news} = 'good'; return $self; } 1; use Daughter; use Son; my $self = Daughter->new()->status; print Dumper($self); $self = Son->new()->set; print Dumper($self); $self = Daughter->new()->other; print Dumper($self); $VAR1 = bless( { 'data' => { 'news' => 'bad' } }, 'Daughter' ); $VAR1 = bless( { 'data' => { 'news' => 'good' } }, 'Son' ); $VAR1 = bless( { 'data' => { 'news' => 'good' } }, 'Daughter' );
do you have some suggestions ?

Replies are listed 'Best First'.
Re: Share data bless hash of parent package with childs packages
by 1nickt (Canon) on Dec 17, 2023 at 14:29 UTC

    Hi,

    Your code does not compile; that makes it hard to help.

    It's also hard to know just what you want to accomplish. If all you want is to not have to use the data hash, just don't use it!

    package Father; sub new { my $class = shift; return bless { news => undef }, $class; } 1;
    package Daughter; use parent qw(Father); sub status { my $self = shift; $self->{news} = 'bad'; return $self; } sub other { my $self = shift; return $self; } 1;
    package Son; use parent qw(Father); sub set { my $self = shift; $self->{news} = 'good'; return $self; } 1;
    use lib '.'; use Daughter; use Son; use Data::Dumper; my $daughter = Daughter->new()->status; print Dumper($daughter); my $son = Son->new()->set; print Dumper($son); $daughter->other; print Dumper($daughter);
    $ perl 11156317.pl $VAR1 = bless( { 'news' => 'bad' }, 'Daughter' ); $VAR1 = bless( { 'news' => 'good' }, 'Son' ); $VAR1 = bless( { 'news' => 'bad' }, 'Daughter' );

    Update: improved example

    Hope this helps. But it likely won't because I have likely misunderstood your problem.


    The way forward always starts with a minimal test.

      Maybe the OP doesn't want to really share data, but wants the Parent class to provide fallback data. But maybe that shouldn't be per-class but more per-instance. Anyway, I would also recommend the OP use a getter/setter approach instead of reaching into the objects:

      sub get( $self, $item ) { if( exists $self->{data}->{ $item }) { return $self->{data}->{ $item } } elsif( $self->{parent_data}->{ $item }) { return $self->{parent_data}->{ $item } } } sub set( $self, $item, $value ) { return $self->{data}->{ $item } = $value; }
Re: Share data bless hash of parent package with childs packages
by Anonymous Monk on Dec 19, 2023 at 11:28 UTC

    First of all, if you are serious about this then you should create a working, minimal example of what you try to achieve. Preferably with test cases where it should fail and succeed.

    Now to what I imagine you want to achieve with the help from the posts of the other monks here, I can see a few options:

    First and simplest: use a state variable in Father to contain the data to be shared among parent and child classes. The drawback of this is that ALL instances of Father will share this data.

    package Father; use strict; use warnings; use 5.010; sub new { my $class = shift; state $shared_data = {}; my $self = { 's' => $shared_data }; bless $self, $class; } sub s { return $_[0]->{s} } 1;
    package Daughter; # or Son use strict; use warnings; use 5.010; use parent qw(Father); 1;
    use strict; use warnings; use lib '.'; use Daughter; use Son; my $d = Daughter->new(); my $s = Son->new(); $d->s()->{'news'} = 'bad'; print $s->s()->{'news'}."\n"; my $d2 = Daughter->new(); print $d->s()->{'news'}."\n"; $d2->s()->{'news'} = 'bad123'; print $s->s()->{'news'}."\n"; print $d->s()->{'news'}."\n"; print $d2->s()->{'news'}."\n"; # prints bad bad bad123 bad123 bad123

    The second option is to use the so-called factory method. Father is created with caller-supplied shared data. Then Daughters and Sons are still separate classes but their instantiation should be ONLY via the Father (you can change their constructor name to be _new and pretend that nobody will notice, in proper OO this is achieved with private constructors etc.) All such subclassed objects will share the same data:

    my $shared_data = {}; my $father = Father->new($shared_data); my $d = $father->new_daughter(); ...

    The benefit of this approach is that only children of a specific father will share data. So you can have multiple unhappy families as opposed to a single happy family as per Tolstoy's insigtful observation: Happy families are all alike; every unhappy family is unhappy in its own way.

    I leave the implementation to you. And please put more effort if you want help.

    bw, bliako

      duh! it seems i cleared my cookies before posting
        That's what "Theme Configuration" in Display Settings is for ;-)😉

        🔜🇽️