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

I'm running into a weird problem with overload , I'm overloading dereferencing like with %{} which means I can't access the objects attributes inside the methods without causing an infinite loop.

What am I missing?

While writing this I'm having an idea...

Cheers Rolf
(addicted to the Perl Programming Language :)
see Wikisyntax for the Monastery

Update

I just discovered eval no overload mentioned in the docs, will give it a try ... :)

Replies are listed 'Best First'.
Re: De-Overload reference?
by choroba (Cardinal) on Apr 16, 2024 at 18:21 UTC
    Update: Old contents replaced.

    I tried to use

    overload->unimport('%{}');

    It kind of works in the way it makes the reference available, but I can't make it overloaded again.

    The same holds for

    eval 'no overload'
    .

    It works, but I can't make the object overloaded back again.

    Update 2:

    I made it work nicely as I intended:

    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; { package LanX; use overload '%{}' => \&_nothing, '""' => sub { $_[0]->_underload(\&_value) }; sub new { bless {value => $_[1]}, $_[0] } sub inc { $_[0]->_underload(sub { ++$_[0]->{value} }) } sub value { $_[0]->_underload(\&_value) } sub _nothing { { value => 'nothing' } } sub _value { $_[0]->{value} } sub _underload { my ($self, $sub) = @_; overload->unimport('%{}'); my $v = $self->$sub; overload->import('%{}' => \&_nothing); return $v } } my $l = 'LanX'->new(12); say "deref\t" => $l->{value}; # nothing say "l\t" => $l; # 12 say "deref\t" => $l->{value}; # nothing say "inc\t" => $l->inc; # 13 say "l\t" => $l; # 13 say "inc\t" => $l->inc; # 14 say "l\t" => $l; # 14 say "deref\t" => $l->{value}; # nothing

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Cool, thanks. Forgot about unimport.

      Tho I'm not sure if deactivated overload for the whole class doesn't bear the danger of a race condition with another instance in a parallel thread.

      I just had the idea to just temporarily bless this $self to another neutral class.

      There is also a tip in the docs I want to try out tomorrow.

      Thanks again :)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

        > I'm not sure if deactivated overload for the whole class doesn't bear the danger of a race condition with another instance in a parallel thread.

        #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use threads; use threads::shared; my $done :shared; my $t = 'threads'->create(sub { my %count; my $l2 = 'LanX'->new(42); # <- You can move this into the below l +oop, too. until ($done) { ++$count{ $l2->{value} }; } for my $key (keys %count) { say "$key: $count{$key}"; } }); { package LanX; use overload '%{}' => \&_nothing, '""' => sub { $_[0]->_underload(\&_value) }; sub new { bless {value => $_[1]}, $_[0] } sub inc { $_[0]->_underload(sub { ++$_[0]->{value} }) } sub value { $_[0]->_underload(\&_value) } sub _nothing { { value => 'nothing' } } sub _value { $_[0]->{value} } sub _underload { my ($self, $sub) = @_; overload->unimport('%{}'); my $v = $self->$sub; sleep 1 if 0 == threads->tid; overload->import('%{}' => \&_nothing); return $v } } my $l = 'LanX'->new(12); say "deref\t" => $l->{value}; # nothing say "l\t" => $l; # 12 say "deref\t" => $l->{value}; # nothing say "inc\t" => $l->inc; # 13 say "l\t" => $l; # 13 say "inc\t" => $l->inc; # 14 say "l\t" => $l; # 14 say "deref\t" => $l->{value}; # nothing $done = 1; $t->join;

        > the idea to just temporarily bless this $self to another neutral class

        Brilliant idea. Seems less ugly, but it's not 100% clear why it's there, so probably needs a comment or a good name for the class.

        sub _underload { my ($self, $sub) = @_; my $class = ref $self; bless $self, 'Cancel::LanX::So::We::Can::Dereference'; my $v = $self->$sub; sleep 1 if 0 == threads->tid; bless $self, $class; return $v }

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
        I thought threads got their own copy of the interpreter. Do they share package stashes?
Re: De-Overload reference?
by NERDVANA (Priest) on Apr 17, 2024 at 19:04 UTC
    If you have a blessed hashref that overloads hashref access, I would think the best way to handle it is change the type of reference you are blessing, or switch to inside-out attributes.
    perl -E ' use v5.36; use overload q{%{}} => sub { { foo => 1 } }; sub foo { $_[0]->$*->{foo} } my $x= bless \{ foo => 2 }, "main"; say $x->foo; '
    perl -E ' use v5.36; use Scalar::Util "refaddr"; use overload q{%{}} => sub { { foo => 1 } }; our %attrs; sub new { my $self= bless {}, shift; $attrs{refaddr $self}= { @_ }; $s +elf } sub DESTROY { delete $attrs{refaddr $_[0]} } sub foo { $attrs{refaddr $_[0]}{foo} } my $x= main->new(foo => 2); say $x->foo; '
      Hmm ... inside outs are an option, forgot about them. Thanks. :)

      But is there a reason why you make %attr a package-var? I'd rather use a lexical closure var my %attr

      FWIW: Using a scalar-ref as object is clever, but in this case I'm overloading all deref-operators, hence we are back to the original problem.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

        But is there a reason why you make %attr a package-var?

        In case a sub-class wants to inspect (or extend) my fields. I'm in the opposite camp as Ovid.

      What problem are you trying to fix?

      It appears you think the following is an example of the problem:

      use v5.36; use overload q{%{}} => sub { { foo => 1 } }; sub foo { $_[0]->{foo} } my $x= bless { foo => 2 }, "main"; say $x->foo;

      But there's no infinite loop in that program, and the OP asks how to avoid an infinite loop.

      [choroba's answer has the same problem, I think.]

      I wish the OP would have provided a demo the problem and stated what they were trying to achieve.

        The code you posted here (without the hash-ref-ref) returns '1', and the code I posted returns '2'.

        In other words, the problem here is that the method 'foo' is accessing the output of the overridden ref operator instead of the true value stored within the object. My example using a hash-ref-ref returns the true value from method foo.

        try to access $self->{foo} (to get the 2) INSIDE q{%{}} => sub { { foo => 1 } };

        I even had core dumps while trying to use Data::Dump::pp(\@_)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

Re: De-Overload reference?
by ikegami (Patriarch) on Apr 17, 2024 at 13:52 UTC

    Returning the variable itself from %{}? It sounds like you should be using magic instead of overloading. What are you trying to achieve?