Jak nadpisać dzialanie operatora w perlu?

0

Cześć, testuję niezbyt urodziwy kawalek w perlu. W tym celu oczywiście mockuję różne funkcje. To jest stosunkowo łatwe, np.

BEGIN {
    *CORE::GLOBAL::open = sub {
       #…
    }
}

Problemów nastręczają operatory, bo nie znam żadnej składni do ich definiowania. Wiem tylko, że przeważnie mapują się one na inne funkcje, np <> na readline, to działa, jest w porządku. Mam natomiast problem z operatorem -e. Gdzieś czytałem, że używa funkcji stat, ale chyba nie w tej implementacji (5.32, Linux). Ktoś ogarnięty w trzewiach perla ma może jakiś pomysł, gdzie szukać poszlak, @PerlMonk?

7

Operatory testów są pod tym względem wyjątkowe, bo przeładowujesz wszystkie albo żadne. Funkcja podpięta do operatora testu otrzymuje jako argumenty literę operatora (dla -e jest to e, dla -f jest to f) i wyrażenie z jego prawej strony.
Przykład:

#!/usr/bin/perl
use warnings;

BEGIN {
	sub muminki {
		return 2 + 2;
	}

	use overload(
		'-' => sub {
			my ($left, $right) = @_;
			return 11;
		},
		'+' => \&muminki,
		'-X' => sub {
			#operator testów
			my ($opType, $path) = @_;
			print "Operator '$opType'. Argument: '$path'\n";
			return;
		}
	);
}

if (-e '/tmp') {
	print "Kaczka!\n";
} else {
	print "Dziwaczka\n";
}

Ten przykład jest z jednej strony dobry, że operatory podawane są w stringach. Z drugiej strony ten sposób jest zależny od implementacji bardziej, niż np. *CORE::GLOBAL::open. W końcu overload to makro a nie słowo kluczowe. Efekt? Potrafi nie działać kompletnie nie wiadomo dlaczego.
Kolejna sprawa: moduły i klasy. Nie zawsze można przeładować operator w bieżącym pliku i trzeba zrobić to w module albo klasie. To kwestia kolejności ładowania funkcji. Chociażby funkcja printf może być niedostępna w bloku BEGIN. O tym, że coś poszło w innej kolejności, niż spodziewa się użytkownik, można dowiedzieć się debugując kod.
Dla innych przykładów musiałbym pogrzebać na dysku a tego nie mam pod ręką. Ogólnie jest z tym sporo zabawy, żeby zadziałało jak należy. Sam nad tym siedziałem kawał czasu, więc nie ma co się dziwić, jeśli nie działa od razu :) . Tak, temat jest ciężki. To, że język udostępnia taką możliwość nie znaczy, że działa wszędzie tak samo.

1

@PerlMonk: Z tego co czytałem, to overload działa tylko dla obiektów definiowanych klas, więc chyba nie da się w ten sposób zrobić Ten kod niestety nie działa. Jeszcze gdzieś na sieci widziałem rozwiązanie przy ozyciu Filter::Simple, ale w tym przypadku też nie zadziałało. Z tego co widzę, wcale nie musi być rozwiązania na ten problem. W końcu pewnie zrobię to na pałę i podmienię wywołania przed wykonaniem testu. :D

1

Ja sam wczoraj chciałem sprawdzić ten temat i dla różnych operatorów działało różnie :D . Z Filter::Simple nie chciałem się bawić, bo od tego momentu zaczynają się już straszne rzeczy - skomplikowane i nieczytelne. Pewnie gramatyka języka się zmieniła i to, co działało kiedyś, teraz nic nie daje. Może być tak, że nawet, jeśli nadpiszesz funkcję, to po drodze się ta zmiana zgubi, bo interpreter wygeneruje w to miejsce swoją wersję.

1 użytkowników online, w tym zalogowanych: 0, gości: 1