#!/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;