Setiap objek dapat diwujudkan sebagai teks, dan bentuk teks itu menentukan keterbacaan keluaran program maupun kemudahan menelusuri kesalahan. Topik ini membahas to_s dan inspect sebagai dua representasi string sebuah objek, cara menimpa to_s pada kelas sendiri, serta tiga metode kesetaraan, yaitu ==, eql?, dan equal?. Setelah membacanya, keluaran objek buatan sendiri dapat dirancang secara sadar dan perbedaan ketiga metode kesetaraan dapat dijelaskan.
Dua representasi string#
Ruby menyediakan dua metode konversi ke teks dengan tujuan berbeda. Metode to_s mengubah objek menjadi string untuk ditampilkan, sedangkan inspect menghasilkan representasi untuk keperluan debug, yaitu bentuk yang menampilkan tanda kutip dan tipe datanya sehingga isi objek lebih mudah diperiksa. Metode puts dan interpolasi memanggil to_s secara otomatis, sedangkan p memanggil inspect.
teks = "suhu 30 derajat"
puts teks
p tekssuhu 30 derajat
"suhu 30 derajat"Keluaran pertama tidak memuat tanda kutip karena itulah bentuk to_s dari string tersebut, sedangkan keluaran kedua memuat tanda kutip karena itulah bentuk inspect-nya. Perbedaan ini berguna saat menelusuri program, misalnya "30" dan 30 tampak sama pada puts, tetapi terlihat berbeda pada p karena satu di antaranya menyertakan tanda kutip. Untuk objek buatan sendiri yang belum menimpa kedua metode itu, representasinya berupa #<NamaKelas:0x...>, yaitu nama kelas beserta alamat memori yang berubah setiap sesi, sehingga keluarannya tidak dapat diandalkan.
Kedua metode itu dimiliki hampir semua objek karena diwarisi dari Object, dan setiap kelas bebas menimpanya. Pembagian kerjanya tetap, yaitu to_s untuk tampilan yang nyaman dibaca dan inspect untuk kejelasan saat debug. Karena itulah p, dan bukan puts, yang dipilih ketika isi objek perlu diperiksa lebih dekat.
Menimpa to_s pada kelas sendiri#
Kelas buatan sendiri dapat menyediakan representasi yang terbaca dengan mendefinisikan metode to_s yang mengembalikan string. Setelah itu, setiap puts dan interpolasi yang melibatkan instansnya otomatis menggunakan bentuk tersebut tanpa perlu memanggil metodenya secara eksplisit.
# Kelas Buku dengan to_s yang ditimpa, dipakai puts dan interpolasi.
class Buku
def initialize(judul, penulis)
@judul = judul
@penulis = penulis
end
def to_s
"#{@judul} karya #{@penulis}"
end
end
buku = Buku.new("Sejarah Batik", "Citra")
puts buku
puts "Dipinjam: #{buku}"
p buku.to_sSejarah Batik karya Citra
Dipinjam: Sejarah Batik karya Citra
"Sejarah Batik karya Citra"Baris puts buku tidak memanggil apa pun selain to_s, dan interpolasi pada "Dipinjam: #{buku}" menjalankan mekanisme yang sama, sehingga keduanya mencetak teks yang terbaca. Baris terakhir menyisipkan to_s ke dalam p, sehingga yang dicetak adalah inspect dari string hasilnya, lengkap dengan tanda kutipnya. Apabila p buku dijalankan tanpa menimpa inspect, keluarannya tetap berbentuk alamat memori, dan itu wajar karena inspect memang diperuntukkan bagi keperluan debug.
Metode to_s yang ditimpa tetap merupakan metode biasa, sehingga dapat dipanggil langsung, disimpan, atau digunakan oleh metode lain. Interpolasi adalah pemanggil to_s yang paling sering bekerja secara implisit, sehingga menimpanya sekaligus memperbaiki setiap pesan yang menyisipkan objek. Apabila representasi debug juga ingin dirapikan, inspect dapat ditimpa dengan cara yang sama, dan p akan menggunakan versi barunya tanpa perubahan apa pun di sisi pemanggil.
Kesetaraan nilai dan identitas#
Tiga metode membandingkan dua objek dengan makna yang berbeda. Metode == membandingkan nilai menurut definisi kelasnya, sehingga dua objek berisi sama dianggap setara. Metode eql? lebih ketat karena menuntut nilai yang sama dan kelas yang sama, dan metode inilah yang digunakan oleh Hash saat mencocokkan kuncinya. Metode equal? mengabaikan keduanya dan hanya menyatakan identitas, yaitu benar atau salahnya dua nama menunjuk objek yang sama persis.
Makna kesamaan pada == ditentukan oleh kelasnya masing-masing. String membandingkan urutan karakternya, Integer membandingkan nilai bilangannya, dan kelas buatan sendiri bebas menetapkan aturannya lewat penimpaan. Akibatnya, pertanyaan apakah dua objek sama selalu bermakna sama menurut kelasnya, dan bukan sama menurut letaknya di memori.
# Kesetaraan nilai dengan ==, eql?, dan identitas dengan equal?.
p 1 == 1.0
p 1.eql?(1.0)
rekap = { 1 => "satu" }
p rekap[1]
p rekap[1.0]
a = "nilai ujian"
b = "nilai ujian"
c = a
p a == b
p a.eql?(b)
p a.equal?(b)
p a.equal?(c)true
false
"satu"
nil
true
true
false
trueDua baris pertama menunjukkan bahwa 1 == 1.0 bernilai true karena nilainya sama menurut perbandingan bilangan, sedangkan 1.eql?(1.0) bernilai false karena Integer dan Float adalah kelas berbeda. Pencarian rekap[1.0] menghasilkan nil dengan alasan yang sama, yaitu Hash mencocokkan kuncinya lewat eql?, sehingga kunci 1 tidak ditemukan ketika pencariannya menggunakan 1.0. Pada bagian akhir, a dan b adalah dua objek dengan isi sama, sehingga keduanya setara menurut == dan eql?. equal? menyatakan false untuk keduanya karena objeknya berbeda, sedangkan equal? menyatakan true untuk c karena c menunjuk objek yang sama dengan a.
Pemilihan metode kesetaraan mengikuti pertanyaan yang diajukan. Untuk membandingkan isi, == sudah cukup dan merupakan pembanding yang paling sering digunakan. Untuk kunci Hash atau kebutuhan ketelitian tipe, eql? yang menentukan, sedangkan equal? digunakan ketika dua nama perlu dipastikan menunjuk objek yang sama. Ketiganya boleh berdampingan dalam satu program karena masing-masing menjawab pertanyaan yang berbeda.
Ringkasan#
putsdan interpolasi memanggilto_ssecara otomatis, sedangkanpmemanggilinspectyang menampilkan bentuk debug.to_spada kelas sendiri ditimpa agar instansnya tercetak sebagai teks yang terbaca di setiapputsdan interpolasi.==membandingkan nilai menurut definisi kelasnya,eql?menambahkan syarat kelas yang sama dan digunakan oleh Hash untuk kuncinya, sedangkanequal?menyatakan identitas objek.- Dua nama yang menunjuk objek yang sama lulus
equal?, sedangkan dua objek berbeda dengan isi sama hanya lulus==daneql?.
Referensi#
- Object#to_s — Dokumentasi Ruby 3.4 — Dokumentasi to_s sebagai representasi string bawaan setiap objek.
- Object#eql? — Dokumentasi Ruby 3.4 — Dokumentasi eql? beserta perannya pada pencocokan kunci Hash.
- BasicObject#equal? — Dokumentasi Ruby 3.4 — Dokumentasi equal? yang menguji identitas objek dan tidak dimaksudkan untuk ditimpa.