to_s dan inspect

Representasi string objek lewat to_s dan inspect, serta metode kesetaraan ==, eql?, dan equal?.

Daftar isi

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.

ruby puts dan p pada string yang sama
teks = "suhu 30 derajat"

puts teks
p teks
text Keluaran
suhu 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.

ruby buku.rb
# 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_s
text Keluaran
Sejarah 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.

ruby kesetaraan.rb
# 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)
text Keluaran
true
false
"satu"
nil
true
true
false
true

Dua 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#

  • puts dan interpolasi memanggil to_s secara otomatis, sedangkan p memanggil inspect yang menampilkan bentuk debug.
  • to_s pada kelas sendiri ditimpa agar instansnya tercetak sebagai teks yang terbaca di setiap puts dan interpolasi.
  • == membandingkan nilai menurut definisi kelasnya, eql? menambahkan syarat kelas yang sama dan digunakan oleh Hash untuk kuncinya, sedangkan equal? menyatakan identitas objek.
  • Dua nama yang menunjuk objek yang sama lulus equal?, sedangkan dua objek berbeda dengan isi sama hanya lulus == dan eql?.

Referensi#