Nilai balik

Nilai balik berbentuk daftar nilai beserta pengenalan wantarray untuk menyesuaikan hasil dengan konteks pemanggil.

Daftar isi

Setiap subrutin menghasilkan satu nilai balik (return value) yang menjadi hasil pemanggilannya. Nilai balik dapat berupa satu nilai maupun daftar nilai, dan bentuk akhirnya dipengaruhi oleh konteks pemanggil, yaitu konteks list atau konteks scalar. Topik ini membahas nilai balik yang muncul dari ekspresi terakhir, pernyataan return, pengembalian beberapa nilai sekaligus, serta fungsi wantarray yang menyesuaikan hasil dengan konteks pemanggil.

Ekspresi terakhir sebagai nilai balik#

Perl tidak memerlukan pernyataan pengembalian yang eksplisit. Nilai balik subrutin adalah nilai dari ekspresi terakhir yang dievaluasi di dalam bloknya, dan nilai itu otomatis menjadi hasil pemanggilan. Oleh karena itu, penugasan hasil pemanggilan ke sebuah variabel, misalnya my $hasil = dua_kali(21);, langsung memperoleh nilai tersebut tanpa pernyataan tambahan. Ekspresi terakhir itu boleh berupa penugasan juga, karena penugasan sendiri merupakan ekspresi yang menghasilkan nilai yang ditugaskan.

Skrip berikut memuat subrutin dua_kali yang baris terakhirnya berupa ekspresi perkalian tanpa penugasan. Ekspresi itulah yang menjadi nilai balik subrutin. Subrutin yang baris terakhirnya berupa pernyataan print akan mengembalikan status pencetakan, dan status itu jarang menjadi hasil yang dimaksud.

perl ekspresi-terakhir.pl
use strict;
use warnings;

# nilai balik adalah nilai dari ekspresi terakhir yang dievaluasi
sub dua_kali {
    my ($angka) = @_;
    $angka * 2;
}

my $hasil = dua_kali(21);
print "Dua kali 21 sama dengan $hasil\n";
text Keluaran
Dua kali 21 sama dengan 42

Titik koma setelah ekspresi terakhir boleh ditulis atau dibiarkan, karena keduanya tidak mengubah nilai baliknya. Yang menentukan adalah ekspresi mana yang dievaluasi paling akhir, sehingga penataan blok perlu dijaga agar baris terakhir benar-benar merupakan hasil yang diinginkan. Pada subrutin yang panjang, kejelasan biasanya lebih terjaga apabila nilai baliknya dinyatakan secara eksplisit dengan return, sebagaimana dibahas pada bagian berikutnya. Kesalahan pemilihan ekspresi terakhir tidak memunculkan warning karena nilainya sah secara sintaks, sehingga hasil yang keliru baru ketahuan pada tahap penggunaan.

Pernyataan return#

Pernyataan return mengakhiri eksekusi subrutin seketika dan menyatakan nilai baliknya secara eksplisit. Subrutin boleh memuat beberapa pernyataan return pada cabang yang berbeda, dan cabang yang tercapai lebih dahulu menentukan hasilnya. Selain memperjelas maksud kode, return juga memungkinkan keluar lebih awal dari tengah subrutin tanpa mengeksekusi sisanya. Pernyataan ini juga mengakhiri seluruh subrutin dari dalam perulangan, sedangkan last hanya menghentikan perulangan yang membungkusnya.

Skrip berikut memeriksa nilai ujian dan mengembalikan teks status sesuai ambang kelulusan. Pernyataan return pertama hanya tercapai apabila kondisinya terpenuhi, sedangkan pemanggil dengan nilai di bawah ambang mencapai return pada baris terakhir.

perl status-kelulusan.pl
use strict;
use warnings;

# return mengakhiri subrutin seketika beserta nilai baliknya
sub status_kelulusan {
    my ($nilai) = @_;
    return "lulus" if $nilai >= 75;
    return "tidak lulus";
}

print status_kelulusan(80), "\n";
print status_kelulusan(60), "\n";
text Keluaran
lulus
tidak lulus

Pernyataan return tanpa nilai juga sah, dan hasilnya bergantung pada konteks, yaitu undef pada konteks scalar dan daftar kosong pada konteks list. Bentuk ini digunakan untuk membatalkan proses ketika syarat tidak terpenuhi, misalnya ketika argumen wajib ternyata kosong, tanpa perlu membawa cabang else yang panjang. Nilai undef hasil return tanpa nilai berbeda dengan nol atau string kosong, dan fungsi defined membedakannya di sisi pemanggil. Pola keluar lebih awal juga menekan jumlah lekukan, karena kondisi khusus ditangani di bagian atas subrutin sebelum logika utamanya ditulis.

Mengembalikan daftar nilai#

Subrutin dapat mengembalikan lebih dari satu nilai sekaligus dalam bentuk daftar. Pada sisi pemanggil, daftar itu diurai dengan penugasan daftar ke variabel-variabel leksikal, sama seperti penguraian @_ di dalam subrutin. Pola ini menggantikan kebutuhan variabel global untuk membawa lebih dari satu hasil keluar dari sebuah perhitungan. Elemen daftarnya berupa scalar, sehingga angka, teks, dan referensi boleh bercampur dalam satu nilai balik.

Skrip berikut menghitung nilai terkecil dan terbesar sekaligus dalam satu penelusuran, lalu mengembalikan keduanya sebagai satu daftar. Tanda kurung pada return ($min, $maks); hanya memperjelas batas daftar, dan bentuk tanpa kurung menghasilkan nilai yang sama. Nilai yang dikembalikan berupa dua scalar yang berdiri sendiri, dan bukan sebuah array.

perl min-maks.pl
use strict;
use warnings;

# subrutin dapat mengembalikan beberapa nilai sekaligus sebagai satu daftar
sub min_maks {
    my @angka = @_;
    my ($min, $maks) = ($angka[0], $angka[0]);
    for my $x (@angka) {
        $min = $x if $x < $min;
        $maks = $x if $x > $maks;
    }
    return ($min, $maks);
}

my ($terkecil, $terbesar) = min_maks(7, 3, 9, 4);
print "Terkecil: $terkecil, terbesar: $terbesar\n";
text Keluaran
Terkecil: 3, terbesar: 9

Subrutin min_maks menelusuri argumennya satu kali, sedangkan desain yang mengembalikan satu nilai saja menuntut penelusuran dua kali atau subrutin terpisah. Jumlah nilai balik tidak terbatas pada dua, dan pemanggil bebas mengurainya. Pemanggil yang hanya memerlukan salah satu nilai dapat mengurai sebagian daftar, dan sisa daftarnya dibuang tanpa memengaruhi hasil yang sudah ditampung. Pemanggil juga dapat menampung seluruh hasilnya menjadi hash apabila subrutin mengembalikan pasangan kunci dan nilai, misalnya my %rekap = hitung_rekap();.

Konteks pemanggil dan wantarray#

Setiap ekspresi Perl dievaluasi dalam konteks tertentu, yaitu konteks list ketika hasilnya ditampung array atau daftar, dan konteks scalar ketika hasilnya ditampung satu variabel scalar. Konteks pemanggil terbawa ke dalam subrutin, sehingga subrutin yang sama dapat menghasilkan bentuk hasil yang berbeda sesuai cara subrutin itu dipanggil.

Fungsi wantarray memberitahukan konteks pemanggil saat ini. Nilainya benar pada konteks list dan salah pada konteks scalar, sehingga subrutin dapat memilih antara mengembalikan seluruh daftar atau ringkasannya, misalnya jumlah elemennya.

Skrip berikut memuat subrutin bacaan_sensor yang menyimpan pembacaan suhu. Pemanggilan dalam konteks list menghasilkan seluruh pembacaan, sedangkan pemanggilan dalam konteks scalar menghasilkan banyaknya pembacaan.

perl wantarray-sensor.pl
use strict;
use warnings;

# wantarray menyesuaikan hasil dengan konteks pemanggil
sub bacaan_sensor {
    my @data = (27.5, 28.1, 26.9, 27.8);
    return wantarray ? @data : scalar @data;
}

my @semua = bacaan_sensor();
my $jumlah = bacaan_sensor();

print "Daftar bacaan: @semua\n";
print "Jumlah bacaan: $jumlah\n";
text Keluaran
Daftar bacaan: 27.5 28.1 26.9 27.8
Jumlah bacaan: 4

Konvensi seperti ini banyak diikuti fungsi bawaan Perl, misalnya keys yang menghasilkan daftar kunci pada konteks list dan banyaknya kunci pada konteks scalar. Dengan mengikuti konvensi yang sama, subrutin buatan sendiri terasa alami bagi pembaca kode Perl lainnya, dan pemanggil tidak perlu menghafal dua nama subrutin untuk dua bentuk hasil.

Kesalahan umum#

Kesalahan yang lazim adalah menampung hasil subrutin yang mengembalikan daftar ke dalam satu variabel scalar dengan harapan memperoleh jumlah elemennya. Pada konteks scalar, daftar yang dikembalikan return dievaluasi sebagai ekspresi koma, dan ekspresi koma menghasilkan elemen terakhirnya, bukan banyaknya elemen. Hasil itu sah secara sintaks, sehingga tidak ada warning yang memperingatkan pemrogram, dan angka yang salah baru ketahuan pada tahap penggunaan.

Skrip berikut memanggil subrutin min_maks yang sama dalam dua konteks. Pemanggilan dalam konteks list menghasilkan pasangan terkecil dan terbesar, sedangkan pemanggilan dalam konteks scalar menghasilkan satu nilai yang tidak sesuai dugaan.

perl konteks-scalar.pl
use strict;
use warnings;

sub min_maks {
    my @angka = @_;
    my ($min, $maks) = ($angka[0], $angka[0]);
    for my $x (@angka) {
        $min = $x if $x < $min;
        $maks = $x if $x > $maks;
    }
    return ($min, $maks);
}

my ($terkecil, $terbesar) = min_maks(7, 3, 9, 4);
print "Konteks list: terkecil $terkecil, terbesar $terbesar\n";

my $satu_nilai = min_maks(7, 3, 9, 4);
print "Konteks scalar: hasilnya $satu_nilai\n";
text Keluaran
Konteks list: terkecil 3, terbesar 9
Konteks scalar: hasilnya 9

Angka 9 pada baris kedua keluaran adalah $maks, yaitu elemen terakhir daftar yang dikembalikan, dan bukan jumlah elemennya. Perbaikannya bergantung pada kebutuhan, yaitu mendeklarasikan variabel berpasangan untuk menerima seluruh daftar, atau menyesuaikan subrutin dengan wantarray sebagaimana dibahas pada bagian sebelumnya.

Ringkasan#

  • Nilai balik subrutin adalah nilai ekspresi terakhir yang dievaluasi, atau nilai yang dinyatakan dengan return.
  • return mengakhiri subrutin seketika, memungkinkan keluar lebih awal, dan dapat mengembalikan daftar nilai sekaligus.
  • Konteks pemanggil menentukan bentuk hasil yang wajar, yaitu konteks list untuk seluruh daftar dan konteks scalar untuk ringkasannya.
  • wantarray benar pada konteks list dan salah pada konteks scalar, sehingga satu subrutin dapat menyesuaikan hasilnya dengan kedua konteks.

Referensi#