W Perl każda funkcja może określać, w jakim kontekście jest wywołana: skalarnym, listowym lub void. Operator wantarray jest używany do określenia kontekstu.
Przykład:
sub foo { if (wantarray) { return (1, 2, 3); # Listowy } else { return 42; # Skalarny } } my @a = foo(); # (1, 2, 3) my $b = foo(); # 42 foo(); # Void context
Cechą charakterystyczną jest to, że jeśli nie używać wantarray prawidłowo, można zwracać nieoczekiwane wartości.
Co zwróci funkcja, jeśli w zależności od kontekstu zwraca tablicę i skalar, a jest wywoływana w kontekście void?
Odpowiedź: W kontekście void zwracana wartość jest ignorowana, jednak sam kod wykonywania gałęzi według wantarray pozostaje. Dlatego należy przewidzieć oddzielne przetwarzanie, jeśli funkcja wykonuje działania uboczne. Na przykład:
sub noisy { if (wantarray) { print "Wywołano w kontekście listowym"; return (1,2,3); } elsif (defined wantarray) { print "Wywołano w skalarze"; return 42; } else { print "Void!"; return; } }
Historia 1
Na projekcie jeden inżynier zapomniał o różnicach kontekstu. Funkcja, która zwracała listę nazw plików, czasami "oddawała" tylko liczbę plików (kontekst skalarny) zamiast samych nazw — prowadziło to do utraty danych przy konkatenacji z innymi wynikami.
Historia 2
Przy opracowywaniu API do analizowania nagłówków funkcje zwracały listę tylko jeśli wyraźnie był tablica po lewej (
my @headers = parse_headers()), a jeśli były wywoływane jakoif (parse_headers()), zwracano tylko pierwszy nagłówek. Błąd znaleziono daleko nie od razu, ponieważ przetwarzanie wyglądało logicznie — ale zachowanie różniło się w różnych częściach projektu.
Historia 3
Funkcja do wyszukiwania dopasowań w pliku zwracała różną liczbę wyników w zależności od kontekstu. W rezultacie, przy przekazywaniu jej do map lub grep występowały nieoczekiwane błędy: map oczekiwał listy, ale otrzymywał undef — a w kontekście skalarnym liczono tylko liczbę znalezionych dopasowań. Problem ujawniono dopiero po kilku wydaniach.