Historia pytania:
Przeciążanie operatorów (overloading) i użycie magických metod to jedna z zaawansowanych stron Perla, niezwykle ważna do tworzenia własnych abstrakcji obiektowych, kompleksowych typów, które wspierają arytmetykę, porównania i konwersje do stringu. Perl pierwotnie nie był ukierunkowany na OOP i przeciążanie, ale od wersji 5 możliwe stało się rozszerzanie standardowego zachowania obiektów poprzez pragma overload i dołączenie specjalnych metod.
Problem:
Kluczowa subtelność — mechanizm jest bardzo elastyczny, ale łatwo popełnić błąd: zachowanie przeciążonego obiektu nie zawsze jest intuicyjne, niepoprawne przeciążenia prowadzą do nieskończonej rekurencji, niepożądanych rzutów i błędów kontekstu. Większość błędów wynika z mieszania przeciążeń stringów i liczb, a także z nieoczekiwanego wywoływania nieopisanych metod operatorów.
Rozwiązanie:
Użyj ściśle pragmy overload dla potrzebnych operatorów, dokładnie opisując sposoby konwersji obiektów, przewiduj działanie w obu kontekstach (liczbowym i stringowym) i wyraźnie opisuj fallbacki. Zaleca się obsługę wszystkich oczekiwanych operatorów i uważne podejście do dziedziczenia przeciążeń.
Przykład kodu:
package MyNum; use overload '+' => 'add', '""' => 'as_string'; sub new { my ($class, $value) = @_; bless { val => $value }, $class; } sub add { my ($self, $other, $swap) = @_; my $sum = $self->{val} + (ref($other) ? $other->{val} : $other); return __PACKAGE__->new($sum); } sub as_string { my $self = shift; return $self->{val}; } 1; # Użycie my $a = MyNum->new(5); my $b = MyNum->new(7); my $c = $a + $b; print "$c "; # 12
Kluczowe cechy:
Pytanie z pułapką 1: Przy przeciążaniu tylko w kontekście stringowym operatorów (""") czy automatycznie zadziała porównanie liczbowe?
Nie, trzeba wyraźnie opisać konwersję liczbową (0+), inaczej Perl spróbuje skonwertować przez metodę stringową, co nie zawsze prowadzi do oczekiwanego rezultatu (na przykład dla eq/== różne zachowanie).
Pytanie z pułapką 2: Czy przeciążony obiekt będzie wspierać operatory, które nie są wyraźnie wymienione w pragma overload?
Nie, tylko te, które są wymienione wyraźnie. Pozostałe używają podstawowego zachowania lub prowadzą do błędów.
Pytanie z pułapką 3: Czy przeciążony operator może zwrócić prosty skalar zamiast obiektu?
Może, ale traci się łańcuch metod i obiektowość, co prowadzi do błędów w dalszym kodzie: albo przestaje działać przeciążenie dla następnych operacji, albo następuje złamanie logiki.
Programista przeciążył tylko operator "+" i "" dla swojego obiektu, zapominając o 0+, -, cmp. Podczas porównania przez "==" uzyskał niepoprawny wynik, ponieważ zadziałało stringification, a nie potrzebna konwersja.
Zalety:
Wady:
Programista używa pragmy overload i obejmuje wszystkie potrzebne operatory (", 0+, +, -, x, <=>), a dla niekompatybilnych — rzuca wyjątek z informacyjnym błędem.
Zalety:
Wady: