in reply to A little overloading conundrum

You can do ugly things to B even from within A:
#!/usr/bin/perl use warnings; use strict; use experimental qw( signatures ); { package My::A; use overload '-' => \− sub minus($x, $y, $swap) { return ref($x)->new( ($y->isa('My::B') ? $x->[0] - $y->{value} : ($x->[0] - $y->[0]) ) * (1, -1)[$swap] ) } sub new($class, $value) { bless [$value], $class } # We can change My::B outside of B, in fact. eval q{ package My::B; my $m = My::B->can('minus') or die 'My::B not loaded'; use overload "-" => sub ($x, $y, $s) { return $y->isa('My::A') ? $y->minus($x, 1) : $m->($x, +$y, $s) } }; } { package My::B; # Can't be changed! use overload '-' => \− sub minus($x, $y, $swap) { my $subtr = $x->{value} - $y->{value}; return ref($x)->new($swap ? -$subtr : $subtr) } sub new($class, $value) { bless {value => $value}, $class } } my $a0 = 'My::A'->new(16); my $a1 = 'My::A'->new(6); my $b0 = 'My::B'->new(16); my $b1 = 'My::B'->new(6); use Data::Dumper; print Dumper A => $a0 - $a1; print Dumper B => $a0 - $b1; print Dumper C => $b0 - $b1; print Dumper D => $b0 - $a1;
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

Replies are listed 'Best First'.
Re^2: A little overloading conundrum
by syphilis (Archbishop) on Mar 09, 2026 at 02:15 UTC
    You can do ugly things to B even from within A

    Yes - and my overloading of the arithmetic operations are done in XSubs - which leads to a fair bit of code clutter, but is procedurally clean and simple (IMO, at least).
    I actually don't fully understand the code you've provided, but I'll certainly try to remedy that when I get the chance. (I'm not really a proper perl programmer.)

    Having decided that Math::MPC's basic arithmetic operators should be capable of handling Math::MPFR objects (since the MPC library already provides functions that perform such arithmetic), it's a fairly simple exercise to insert the few required lines of code into the relevant Math::MPC XSubs.
    If not for this "conundrum", that would be the end of the exercise.
    Math::MPFR, which has no business to engage in arithmetic with Math::MPC objects, could be left as is - with no need to even mention this new capability in the Math::MPFR docs.

    The solution I use is simple enough, but it involves making changes to the Math::MPFR overloading XSubs.

    It's only a matter of inserting one line of code into a new if(condition){} block in each of those XSubs. And it just does a callback to (eg) Math::MPC::overload_minus(mpc_object, mpfr_object, &PL_sv_yes) with the assistance of a 20-line macro.
    I'm happy enough with that, and I've used that technique without issue in a number of cross-class overloading situations - though I have no idea how expensive that solution is.
    There's even no need to check whether Math::MPC has been loaded. If a Math::MPC object has been passed to a Math::MPFR function then we know that perl has loaded Math::MPC.
    It's just a bit annoying that I have to go that extra step.
    It would be much better if I could simply tell perl's overloading process "hey, in this case, use the overloading subroutine of the second object". But ... I can't do that :-((

    Cheers,
    Rob
      I actually don't fully understand the code you've provided, but I'll certainly try to remedy that when I get the chance.

      First up, I wanted to remove the "experimental" requirement - assuming it's not a crucial piece of the demo. (I'm not at all familiar with experimental stuff, and I don't have much interest in it.)
      I've also added some dumps of some more subtractions.
      So, I've arrived at this modified version of choroba's script :
      use warnings; use strict; #use experimental qw( signatures ); { package My::A; use overload '-' => \− # sub minus($x, $y, $swap) { ############ Replaced by next line ## sub minus { my($x, $y, $swap) = (shift, shift, shift); return ref($x)->new( ($y->isa('My::B') ? $x->[0] - $y->{value} : ($x->[0] - $y->[0]) ) * (1, -1)[$swap] ) } # sub new($class, $value) { ############ Replaced by next line ## sub new { my($class, $value) = (shift, shift); bless [$value], $class } # We can change My::B outside of B, in fact. eval q{ package My::B; my $m = My::B->can('minus') or die 'My::B not loaded'; use overload "-" => sub { my($x, $y, $s) = (shift, shift, + shift); return $y->isa('My::A') ? $y->minus($x, 1) : $m->($x, +$y, $s) } }; } { package My::B; # Can't be changed! use overload '-' => \− # sub minus($x, $y, $swap) { ############ Replaced by next line ## sub minus { my($x, $y, $swap) = (shift, shift, shift); my $subtr = $x->{value} - $y->{value}; return ref($x)->new($swap ? -$subtr : $subtr) } # sub new($class, $value) { ############ Replaced by next line ## sub new { my($class, $value) = (shift, shift); bless {value => $value}, $class } } my $a0 = 'My::A'->new(16); my $a1 = 'My::A'->new(6); my $b0 = 'My::B'->new(16); my $b1 = 'My::B'->new(6); use Data::Dumper; print Dumper A => $a0 - $a1; print Dumper B => $a0 - $b1; print Dumper C => $b0 - $b1; print Dumper D => $b0 - $a1; print Dumper AA => $a1 - $a0; print Dumper BB => $b1 - $a0; print Dumper CC => $b1 - $b0; print Dumper DD => $a1 - $b0;
      At this point, I have 2 questions:
      1. Where is can documented ?
      2. How is it that I can use isa even though no features have been enabled ?

      Regarding the first question:
      >perldoc -f can No documentation for perl function 'can' found
      WRT the second question, the perlop documentation says this regarding isa:
      This feature is available from Perl 5.31.6 onwards when enabled by + "use feature 'isa'". This feature is enabled automatically by a "use v5 +.36" (or higher) declaration in the current scope.
      I have done neither of those things. Has perl-5.42.0 automatically called that feature for me ? ... or does it automatically call "use v5.36" ?

      Cheers,
      Rob
        At this point, I have 2 questions:
        1. Where is can documented ?
        2. How is it that I can use isa even though no features have been enabled ?

        From UNIVERSAL:

        UNIVERSAL is the base class from which all blessed references inherit....
        UNIVERSAL provides the following methods:
        $obj->isa( TYPE )
        ...
        $obj->can( METHOD )

        Regarding use feature 'isa', it appears this refers to the experimental isa operator, as opposed to the UNIVERSAL method.

        Hope that helps,

        Athanasius <°(((><contra mundum סתם עוד האקר של פרל,