Pemrograman berorientasi objek pada Perl berangkat dari fondasi yang sederhana, yaitu model klasik berbasis fungsi bless. Topik ini membahas pembentukan kelas melalui package, penulisan konstruktor yang menandai sebuah referensi hash dengan nama kelas, akses atribut melalui metode aksesor, serta pengenalan kelas melalui fungsi ref. Pada akhir topik, satu berkas yang berisi kelas utuh bernama Lingkaran dibuat dan dijalankan untuk menunjukkan keseluruhan mekanismenya.
Package sebagai kelas#
Perl tidak menyediakan kata kunci khusus untuk mendefinisikan kelas. Pada model klasik, kelas hanyalah sebuah package, yaitu ruang nama (namespace) yang mengelompokkan nama subrutin agar tidak bertabrakan dengan subrutin pada package lain. Setiap subrutin yang ditulis di dalam package tersebut menjadi kandidat metode kelasnya, sehingga pernyataan package Lingkaran; yang diikuti beberapa subrutin sudah membentuk kelas bernama Lingkaran.
Yang membedakan metode dari subrutin biasa adalah cara pemanggilannya. Subrutin yang dipanggil melalui operator panah (->) menerima satu argumen tambahan pada posisi pertama, yaitu nama kelas atau objek pemanggilnya. Pemanggilan Lingkaran->new menjadikan string Lingkaran sebagai argumen pertama subrutin new, sedangkan pemanggilan $objek->keliling menjadikan objek tersebut argumen pertamanya. Subrutin yang dirancang menerima argumen pertama semacam inilah yang berperan sebagai metode, dan argumen pertama itu disebut invocant.
Sejak Perl 5.38, bahasa ini menyediakan pula kata kunci class untuk penulisan kelas bawaan, tetapi fitur tersebut masih berstatus eksperimental pada Perl 5.40. Model klasik berbasis package dan bless tetap menjadi fondasi yang tersedia pada setiap instalasi Perl tanpa syarat versi. Pemahaman atas cara kelas terbentuk dari package dan bless juga memudahkan pembacaan kode Perl lama yang masih banyak digunakan.
Konstruktor dengan bless#
Konstruktor adalah metode yang membentuk objek baru dan mengembalikannya. Konvensi Perl menamai konstruktor new, walaupun metode dengan nama lain juga sah. Dalam model klasik, data objek disimpan dalam hash, dan konstruktor membentuk referensi hash tersebut lalu menandainya dengan nama kelas melalui fungsi bawaan bless. Penandaan inilah yang mengubah sebuah referensi hash menjadi objek, karena sejak saat itu referensi tersebut mengingat kelas miliknya.
Bentuk konstruktor yang lazim menerima nama kelas sebagai argumen pertama dan pasangan kunci-nilai sebagai argumen berikutnya. Nama kelas ditampung pada variabel $class, sedangkan sisa argumen dibaca sebagai hash %argumen untuk mengisi atribut awal. Fungsi bless dipanggil dengan dua argumen, yaitu referensi yang akan ditandai dan nama kelasnya. Pola lengkapnya terlihat pada konstruktor minimal berikut.
# tidak-dijalankan
sub new {
my ($class, %argumen) = @_;
my $self = {
jari_jari => $argumen{jari_jari} // 0,
};
return bless $self, $class;
}Baris pertama menampung argumen subrutin, yaitu nama kelas dan pasangan atribut awal. Baris berikutnya membentuk referensi hash yang diisi dengan nilai bawaan melalui operator //, sehingga atribut yang tidak disertakan pemanggil memperoleh nilai yang aman. Baris terakhir menandai referensi tersebut dengan nama kelas, lalu mengembalikannya sebagai objek baru.
Akses atribut melalui metode aksesor#
Atribut objek pada model klasik tersimpan sebagai pasangan kunci dan nilai di dalam hash objeknya, sehingga nilainya dapat dibaca langsung melalui $objek->{jari_jari}. Penulisan langsung seperti itu sah pada skrip kecil, tetapi menautkan kode pemanggil dengan struktur internal kelasnya. Perubahan nama kunci di dalam kelas akan merusak setiap baris yang membaca kunci tersebut dari luar.
Metode aksesor menangani masalah tersebut dengan lapisan fungsi. Aksesor berupa subrutin biasa yang membaca kunci dari hash objek dan mengembalikan nilainya, sedangkan aksesor penulis menerima nilai baru sebagai argumen kedua setelah invocant dan menugaskannya ke kunci yang sesuai. Konvensi yang lazim memberi nama aksesor sama dengan nama atributnya, sehingga metode jari_jari membaca kunci jari_jari dari hash objek. Dengan konvensi ini, seluruh pemanggil dari luar kelas hanya bergantung pada nama metode dan tidak lagi bergantung pada nama kunci, sehingga struktur internal kelas bebas diubah tanpa merusak pemanggilnya. Aksesor penulis mengikuti aturan yang sama, sehingga penugasan nilai baru juga dapat diberi pemeriksaan tambahan di dalam metodenya.
Mengenali kelas melalui fungsi ref#
Setiap referensi dapat diperiksa jenisnya melalui fungsi ref. Referensi hash biasa mengembalikan string HASH, sedangkan referensi yang sudah ditandai bless mengembalikan nama kelasnya. Perilaku ini menjadikan ref cara termudah untuk memastikan sebuah variabel benar-benar objek dari kelas yang diharapkan. Skrip berikut menunjukkan perubahan tersebut pada satu referensi yang sama.
use strict;
use warnings;
# referensi hash biasa belum mengetahui kelas apa pun
my $data = { warna => "merah" };
print "Sebelum bless: ", ref($data), "\n";
# bless menandai referensi yang sama dengan nama kelas
bless $data, "Warna";
print "Sesudah bless: ", ref($data), "\n";Sebelum bless: HASH
Sesudah bless: WarnaString yang dikembalikan ref berubah dari HASH menjadi Warna, padahal kunci dan nilai di dalam hashnya tidak berubah sama sekali. Fungsi bless tidak menyentuh data, tetapi hanya melampirkan nama kelas pada referensinya. Data objek dan identitas kelasnya dengan demikian terpisah, dan keduanya bersatu pada satu referensi yang sama.
Hasil ref selalu berupa nama kelas yang ditandai pada referensinya, tanpa mempertimbangkan rantai pewarisannya. Objek kelas turunan dengan demikian tetap melaporkan nama kelasnya sendiri, bukan nama kelas induk yang diwarisinya. Pemeriksaan keanggotaan yang mencakup pewarisan memerlukan metode isa, sedangkan fungsi blessed dari modul inti Scalar::Util memberikan alternatif lain. Fungsi tersebut mengembalikan undef untuk nilai yang bukan objek, sehingga pemeriksaan jenis referensi terlebih dahulu tidak diperlukan.
Kelas Lingkaran dalam satu berkas utuh#
Bagian ini menyatukan seluruh unsur yang sudah dibahas dalam satu berkas yang dapat dijalankan. Kelas Lingkaran didefinisikan dengan konstruktor, aksesor, dan metode perhitungan, lalu digunakan oleh package main pada berkas yang sama. Simpan kode berikut sebagai lingkaran.pl, lalu jalankan dengan perintah perl lingkaran.pl.
use strict;
use warnings;
# kelas Lingkaran berbasis bless
package Lingkaran;
sub new {
my ($class, %argumen) = @_;
my $self = {
jari_jari => $argumen{jari_jari} // 0,
};
return bless $self, $class;
}
# aksesor pembaca untuk atribut jari_jari
sub jari_jari {
my ($self) = @_;
return $self->{jari_jari};
}
# keliling lingkaran dihitung dari atribut objek
sub keliling {
my ($self) = @_;
return 2 * 3.14159 * $self->{jari_jari};
}
package main;
my $lingkaran = Lingkaran->new(jari_jari => 10);
print "Kelas objek : ", ref($lingkaran), "\n";
print "Jari-jari : ", $lingkaran->jari_jari, "\n";
printf "Keliling : %.2f\n", $lingkaran->keliling;
# data objek tetap berupa hash yang dapat dibaca langsung
$lingkaran->{jari_jari} = 3;
printf "Keliling baru: %.2f\n", $lingkaran->keliling;Kelas objek : Lingkaran
Jari-jari : 10
Keliling : 62.83
Keliling baru: 18.85Keluaran memperlihatkan keseluruhan alurnya. Fungsi ref melaporkan Lingkaran, yang berarti konstruktor berhasil menandai referensinya. Metode jari_jari mengembalikan nilai atribut tanpa menyebut kuncinya, dan metode keliling menghitung hasil dari atribut yang sama. Baris terakhir menugaskan nilai baru melalui akses hash langsung, sehingga metode keliling menghasilkan angka yang berbeda pada pemanggilan berikutnya.
Satu berkas dapat memuat definisi kelas sekaligus kode pemanggilnya karena deklarasi package menandai batas antara keduanya secara tegas. Deklarasi package Lingkaran; menaungi definisi kelasnya, sedangkan deklarasi package main; mengembalikan penulisan program ke ruang nama utama. Pola ini praktis untuk latihan dan eksperimen kecil, sedangkan kelas yang siap digunakan ulang biasanya dipindahkan ke modul berekstensi .pm agar dapat dimuat oleh banyak program.
Kesalahan umum#
Kesalahan pertama adalah menulis bless $self; tanpa argumen kelas. Bentuk satu argumen menandai referensi dengan package yang sedang berjalan, sehingga konstruktor masih bekerja pada kelas aslinya, tetapi menghasilkan objek dengan kelas yang keliru apabila konstruktor itu dipanggil dari kelas anak melalui pewarisan. Kebiasaan yang tepat adalah selalu menuliskan bless $self, $class; dengan nama kelas yang diterima konstruktornya.
Kesalahan kedua adalah memanggil metode sebagai subrutin biasa, misalnya Lingkaran::keliling($lingkaran). Pemanggilan dengan tanda :: melewati mekanisme pencarian metode, sehingga pewarisan dan penimpaan metode tidak berjalan. Panggil metode melalui operator panah agar pencarian kelas tetap bekerja.
Kesalahan ketiga adalah menganggap penugasan objek ke variabel lain menyalin datanya. Objek berupa referensi, sehingga $salinan = $lingkaran; hanya menyalin alamatnya, dan perubahan pada $salinan->{jari_jari} turut mengubah objek aslinya. Salinan yang benar-benar terpisah memerlukan pembentukan objek baru atau penyalinan hash secara eksplisit.
Ringkasan#
- Kelas pada model klasik berupa
package, dan metodenya berupa subrutin yang menerima invocant sebagai argumen pertama. - Konstruktor lazim bernama
new, membentuk referensi hash berisi atribut awal, lalu menandainya dengan nama kelas melaluibless $self, $class. - Atribut dapat dibaca langsung melalui
$objek->{kunci}, tetapi metode aksesor melindungi pemanggil dari perubahan struktur internal kelas. ref($objek)mengembalikan nama kelasnya, sedangkanrefatas referensi hash biasa mengembalikanHASH.
Referensi#
- perlobj — Perl documentation
— Dokumentasi resmi model objek Perl, termasuk
bless, konstruktor, dan akses atribut. - perlootut — Perl documentation — Tutorial pemrograman berorientasi objek Perl beserta panduan memilih pendekatan objeknya.
- perlref — Perl documentation — Menguraikan referensi, yaitu dasar data objek pada model klasik.