Tipe Data

Tipe Data #

Satu hal yang membuat Ruby terasa berbeda dari bahasa seperti Java atau C adalah kamu tidak pernah perlu mendeklarasikan tipe data secara eksplisit. Tulis x = 42 dan Ruby tahu itu Integer. Tulis x = "halo" dan Ruby tahu itu String. Tapi “dinamis” bukan berarti “tanpa tipe” — setiap nilai di Ruby adalah objek dengan tipe yang jelas, dan setiap tipe punya perilaku dan method yang berbeda. Memahami karakteristik masing-masing tipe data, kapan menggunakannya, dan bagaimana mengonversi antar tipe adalah fondasi yang menentukan kualitas kode Ruby yang kamu tulis.

Semua Nilai adalah Objek #

Sebelum membahas tipe satu per satu, ada konsep yang penting untuk dipahami: di Ruby, setiap nilai adalah objek — termasuk angka, boolean, bahkan nil. Tidak ada tipe primitif seperti di Java atau C. Artinya, semua nilai punya method yang bisa dipanggil.

42.class          # => Integer
3.14.class        # => Float
"halo".class      # => String
:simbol.class     # => Symbol
true.class        # => TrueClass
false.class       # => FalseClass
nil.class         # => NilClass
[].class          # => Array
{}.class          # => Hash
(1..10).class     # => Range

# Bahkan angka punya method
42.even?          # => true
42.to_s           # => "42"
42.times { |i| print "#{i} " }   # => 0 1 2 3 ... 41
flowchart TD
    A[Semua nilai di Ruby] --> B[Object]
    B --> C[Numeric]
    B --> D[String]
    B --> E[Symbol]
    B --> F[Array]
    B --> G[Hash]
    B --> H[NilClass]
    B --> I[TrueClass / FalseClass]
    B --> J[Range]
    C --> K[Integer]
    C --> L[Float]
    C --> M[Rational]
    C --> N[Complex]

Integer #

Integer menyimpan bilangan bulat — positif, negatif, atau nol — tanpa batas ukuran. Ruby secara otomatis menangani bilangan yang sangat besar tanpa overflow.

# Deklarasi berbagai Integer
umur        = 25
suhu        = -10
nol         = 0
populasi    = 270_000_000      # underscore sebagai pemisah ribuan
besar_sekali = 10 ** 100       # googol — Ruby menanganinya tanpa masalah

# Method umum Integer
puts 17.even?        # => false
puts 17.odd?         # => true
puts -5.abs          # => 5
puts 255.to_s(2)     # => "11111111" (konversi ke biner)
puts 255.to_s(16)    # => "ff" (konversi ke heksadesimal)
puts 10.gcd(6)       # => 2 (greatest common divisor)
puts 10.lcm(6)       # => 30 (least common multiple)

Literal Integer dalam Berbagai Basis #

Ruby mendukung penulisan literal integer dalam basis desimal, biner, oktal, dan heksadesimal langsung di kode:

desimal      = 255         # basis 10 (standar)
biner        = 0b11111111  # basis 2  — prefix 0b
oktal        = 0377        # basis 8  — prefix 0 atau 0o
heksadesimal = 0xFF        # basis 16 — prefix 0x

puts desimal == biner        # => true (semua nilai 255)
puts desimal == oktal        # => true
puts desimal == heksadesimal # => true

Perhatian: Integer Division #

Pembagian dua Integer menghasilkan Integer — sisa desimal dibuang, bukan dibulatkan.

# ANTI-PATTERN: mengharapkan hasil desimal dari pembagian integer
puts 7 / 2     # => 3  (bukan 3.5!)
puts 1 / 3     # => 0  (bukan 0.333!)

# BENAR: gunakan Float di salah satu operand
puts 7.0 / 2   # => 3.5
puts 7 / 2.0   # => 3.5
puts 7.fdiv(2) # => 3.5  (cara paling idiomatik)

# Atau konversi eksplisit
puts 7.to_f / 2  # => 3.5

Float #

Float menyimpan bilangan desimal menggunakan representasi floating-point presisi ganda (64-bit IEEE 754). Cocok untuk kalkulasi ilmiah dan finansial ringan, tapi punya keterbatasan presisi yang perlu dipahami.

pi        = 3.14159265358979
suhu      = -10.5
persen    = 0.15
notasi_e  = 1.5e3    # notasi ilmiah: 1.5 × 10³ = 1500.0

# Method umum Float
puts 3.7.ceil     # => 4   (bulatkan ke atas)
puts 3.7.floor    # => 3   (bulatkan ke bawah)
puts 3.7.round    # => 4   (bulatkan ke terdekat)
puts 3.14159.round(2)  # => 3.14  (bulatkan ke n desimal)
puts -3.7.abs     # => 3.7
puts 2.0.infinite?  # => nil (false)
puts (1.0/0).infinite?  # => 1  (positive infinity)
puts (0.0/0).nan?       # => true (Not a Number)

Masalah Presisi Float #

Float tidak bisa merepresentasikan semua bilangan desimal secara persis — ini bukan bug Ruby, tapi keterbatasan fundamental representasi floating-point binary.

# ANTI-PATTERN: membandingkan Float secara langsung
puts 0.1 + 0.2 == 0.3   # => false !
puts 0.1 + 0.2           # => 0.30000000000000004

# ANTI-PATTERN: menggunakan Float untuk kalkulasi uang
harga  = 19.99
jumlah = 3
total  = harga * jumlah
puts total   # => 59.97000000000001  (bukan 59.97!)

# BENAR: gunakan BigDecimal untuk kalkulasi finansial
require 'bigdecimal'
harga  = BigDecimal("19.99")
jumlah = 3
total  = harga * jumlah
puts total.to_s('F')   # => "59.97"

# BENAR: bandingkan Float dengan toleransi (epsilon)
def float_sama?(a, b, epsilon = 1e-9)
  (a - b).abs < epsilon
end
puts float_sama?(0.1 + 0.2, 0.3)   # => true
Jangan pernah menggunakan Float untuk menyimpan atau menghitung nilai uang. Gunakan BigDecimal (dari standard library) atau simpan nilai uang sebagai Integer dalam satuan terkecil (sen atau rupiah), lalu tampilkan dengan format yang sesuai. Kesalahan presisi Float dalam konteks finansial bisa menyebabkan selisih yang nyata di skala transaksi besar.

String #

String adalah urutan karakter yang bisa dimanipulasi dengan ratusan method bawaan. Ini adalah tipe data yang paling sering digunakan dalam hampir semua program.

# Dua cara membuat string
dengan_kutip_ganda  = "Selamat datang, #{Time.now.year}!"  # interpolasi aktif
dengan_kutip_tunggal = 'Selamat datang, #{tahun}!'          # interpolasi tidak aktif

# Heredoc — untuk string multi-baris yang panjang
pesan = <<~HEREDOC
  Halo, ini adalah string
  yang sangat panjang dan
  mencakup beberapa baris.
HEREDOC

puts pesan.strip

Method String yang Sering Dipakai #

teks = "  Ruby adalah bahasa pemrograman yang indah!  "

# Membersihkan whitespace
teks.strip      # => "Ruby adalah bahasa pemrograman yang indah!"
teks.lstrip     # => "Ruby adalah..." (hapus kiri saja)
teks.rstrip     # => "  Ruby adalah..." (hapus kanan saja)

# Transformasi huruf
teks.upcase     # => "  RUBY ADALAH..."
teks.downcase   # => "  ruby adalah..."
teks.capitalize # => "  ruby..." → "  Ruby..."  (hanya huruf pertama)
teks.swapcase   # => huruf besar jadi kecil dan sebaliknya

# Pengecekan konten
teks.include?("Ruby")      # => true
teks.start_with?("  Ruby") # => true
teks.end_with?("!")        # => true
teks.empty?                # => false
teks.match?(/bahasa/)      # => true (regex)

# Manipulasi
teks.gsub("Ruby", "Python")        # ganti semua kemunculan
teks.sub("bahasa", "language")     # ganti hanya yang pertama
teks.split(" ")                    # pecah menjadi array
teks.reverse                       # balik urutan karakter
teks.chars                         # pecah menjadi array karakter
teks.bytes                         # pecah menjadi array byte

# Ukuran
teks.length   # => 48 (jumlah karakter)
teks.size     # alias untuk length
teks.bytesize # jumlah byte (berbeda untuk karakter multibyte)

String Immutability dengan freeze #

# frozen_string_literal: true   ← aktifkan di awal file untuk performa lebih baik

nama = "Rina"
nama.frozen?   # => true (jika magic comment aktif)

nama << " Wijaya"   # => FrozenError jika frozen
nama += " Wijaya"   # => OK — membuat String baru, bukan memodifikasi yang lama

Symbol #

Symbol adalah identifier yang ringan dan immutable. Ia mirip String, tapi punya karakteristik unik: setiap Symbol dengan nama yang sama merujuk ke objek yang persis sama di memori, tidak peduli berapa kali kamu menulisnya.

# Deklarasi Symbol
status   = :aktif
role     = :admin
metode   = :get

# Symbol vs String — perbedaan identitas objek
puts "aktif".object_id == "aktif".object_id  # => false (dua objek berbeda)
puts :aktif.object_id  == :aktif.object_id   # => true  (objek yang sama!)

# Method Symbol
puts :hello.to_s        # => "hello" (konversi ke String)
puts "hello".to_sym     # => :hello  (konversi ke Symbol)
puts :hello.upcase      # => :HELLO
puts :hello_world.length  # => 11

Kapan Gunakan Symbol vs String #

# ANTI-PATTERN: menggunakan String sebagai key Hash
config = {
  "host"     => "localhost",
  "port"     => 5432,
  "database" => "app_db"
}
# Setiap akses "host" membuat objek String baru di memori

# BENAR: gunakan Symbol sebagai key Hash — lebih efisien
config = {
  host:     "localhost",
  port:     5432,
  database: "app_db"
}
# :host adalah objek tunggal yang selalu sama

# ANTI-PATTERN: Symbol untuk teks yang ditampilkan ke user
puts :selamat_datang   # kurang tepat, Symbol bukan untuk teks UI

# BENAR: Symbol untuk identifier internal, String untuk teks yang ditampilkan
status_aktif = :aktif        # identifier internal
pesan_ui     = "Selamat datang!"  # teks untuk user
Panduan memilih Symbol vs String:
  Symbol jika:
  ✓ Digunakan sebagai key Hash
  ✓ Identifier internal (status, role, event name)
  ✓ Nama method yang dioper sebagai argumen
  ✓ Nilai yang dibandingkan, bukan ditampilkan

  String jika:
  ✓ Teks yang ditampilkan ke pengguna
  ✓ Konten yang perlu dimanipulasi (split, gsub, dll)
  ✓ Data yang dibaca dari input atau file eksternal
  ✓ Nilai yang berubah-ubah atau tidak terbatas jumlahnya

Array #

Array adalah koleksi terurut yang bisa menampung objek dari tipe apapun, termasuk campuran berbagai tipe sekaligus. Indeks dimulai dari 0, dan indeks negatif menghitung dari belakang.

# Membuat Array
buah    = ["apel", "mangga", "jeruk", "nanas"]
angka   = [1, 2, 3, 4, 5]
campur  = [1, "dua", :tiga, 4.0, nil, true]
kosong  = []
kata    = %w[satu dua tiga empat]  # shorthand untuk array string

# Akses elemen
puts buah[0]      # => "apel"
puts buah[-1]     # => "nanas" (dari belakang)
puts buah[1..2]   # => ["mangga", "jeruk"] (range)
puts buah[1, 2]   # => ["mangga", "jeruk"] (mulai index 1, ambil 2 elemen)
puts buah.first   # => "apel"
puts buah.last    # => "nanas"
puts buah.first(2)  # => ["apel", "mangga"]

Manipulasi Array #

daftar = [3, 1, 4, 1, 5, 9, 2, 6]

# Tambah dan hapus elemen
daftar.push(7)         # tambah di belakang
daftar << 8            # alias push — paling idiomatik
daftar.unshift(0)      # tambah di depan
daftar.pop             # hapus dan kembalikan elemen terakhir
daftar.shift           # hapus dan kembalikan elemen pertama
daftar.delete(1)       # hapus semua elemen dengan nilai 1

# Transformasi — semuanya mengembalikan Array baru (non-destructive)
daftar.sort            # => [2, 3, 4, 5, 6, 9]
daftar.sort.reverse    # => [9, 6, 5, 4, 3, 2]
daftar.uniq            # => [3, 4, 5, 9, 2, 6] (hapus duplikat)
daftar.flatten         # ratakan array bersarang
daftar.compact         # hapus semua nil
daftar.map { |n| n * 2 }    # transformasi setiap elemen
daftar.select { |n| n > 4 } # filter elemen yang memenuhi kondisi
daftar.reject { |n| n > 4 } # kebalikan select
daftar.reduce(:+)            # jumlahkan semua elemen
daftar.min                   # elemen terkecil
daftar.max                   # elemen terbesar
daftar.sum                   # total (shortcut dari reduce(:+))
daftar.count { |n| n > 3 }  # hitung yang memenuhi kondisi

Operasi Himpunan #

a = [1, 2, 3, 4, 5]
b = [3, 4, 5, 6, 7]

puts (a | b).inspect   # => [1, 2, 3, 4, 5, 6, 7]  (union)
puts (a & b).inspect   # => [3, 4, 5]               (intersection)
puts (a - b).inspect   # => [1, 2]                  (difference)
puts (a + b).inspect   # => [1, 2, 3, 4, 5, 3, 4, 5, 6, 7] (concat)

Hash #

Hash adalah koleksi pasangan kunci-nilai, mirip dictionary atau map di bahasa lain. Di Ruby modern, Hash mempertahankan urutan penyisipan.

# Membuat Hash — dua sintaks yang valid
# Sintaks lama (hash rocket):
profil = { "nama" => "Budi", "umur" => 30 }

# Sintaks modern (symbol key) — lebih ringkas dan umum:
profil = { nama: "Budi", umur: 30, kota: "Jakarta" }

# Akses nilai
puts profil[:nama]    # => "Budi"
puts profil[:umur]    # => 30
puts profil[:email]   # => nil (key tidak ada, tidak error)
puts profil.fetch(:email)           # => KeyError!
puts profil.fetch(:email, "N/A")    # => "N/A" (default jika tidak ada)

Manipulasi Hash #

data = { a: 1, b: 2, c: 3, d: 4 }

# Tambah, ubah, hapus
data[:e] = 5          # tambah key baru
data[:a] = 10         # ubah nilai
data.delete(:b)       # hapus key :b

# Pengecekan
data.key?(:c)         # => true
data.value?(3)        # => true
data.empty?           # => false
data.size             # => 4
data.keys             # => [:a, :c, :d, :e]
data.values           # => [10, 3, 4, 5]

# Iterasi
data.each { |k, v| puts "#{k}: #{v}" }
data.each_key   { |k| puts k }
data.each_value { |v| puts v }

# Transformasi
data.map    { |k, v| [k, v * 2] }.to_h   # gandakan semua nilai
data.select { |k, v| v > 3 }             # hanya pasangan dengan nilai > 3
data.reject { |k, v| v > 3 }             # kebalikan select
data.any?   { |k, v| v > 3 }             # apakah ada yang memenuhi?
data.all?   { |k, v| v > 0 }             # apakah semua memenuhi?
data.min_by { |k, v| v }                 # pasangan dengan nilai terkecil
data.sort_by { |k, v| v }               # urutkan berdasarkan nilai

# Merge — gabungkan dua hash
defaults = { timeout: 30, retries: 3, debug: false }
overrides = { timeout: 60, debug: true }
hasil = defaults.merge(overrides)
# => { timeout: 60, retries: 3, debug: true }

Hash dengan Default Value #

# ANTI-PATTERN: pengecekan nil manual sebelum akses nested hash
config = {}
config[:db] ||= {}
config[:db][:host] = "localhost"

# BENAR: Hash dengan default value
counter  = Hash.new(0)    # default value 0 untuk key apapun
counter[:apel] += 1
counter[:mangga] += 3
puts counter.inspect   # => {apel: 1, mangga: 3}

# Default value dengan blok — lebih powerful
kelompok = Hash.new { |h, k| h[k] = [] }
["Rina", "Budi", "Ani"].each_with_index do |nama, i|
  kelompok[i % 2] << nama
end
puts kelompok.inspect  # => {0=>["Rina", "Ani"], 1=>["Budi"]}

Boolean — TrueClass dan FalseClass #

Ruby tidak punya tipe Boolean yang tunggal. Sebaliknya, ada dua kelas terpisah: TrueClass (untuk nilai true) dan FalseClass (untuk nilai false). Hanya ada satu instance dari masing-masing kelas ini di seluruh program.

puts true.class    # => TrueClass
puts false.class   # => FalseClass

# Truthy dan Falsy di Ruby
# Hanya nil dan false yang falsy — SEMUA nilai lain truthy!
puts !!nil    # => false (falsy)
puts !!false  # => false (falsy)
puts !!0      # => true  (0 adalah truthy di Ruby, berbeda dari C/JS!)
puts !!""     # => true  (string kosong truthy di Ruby!)
puts !![]     # => true  (array kosong truthy di Ruby!)
puts !!:sym   # => true
# ANTI-PATTERN: membandingkan boolean dengan == true atau == false
if user.aktif? == true    # redundan
  # ...
end

if nilai == false         # lebih baik pakai unless
  # ...
end

# BENAR: gunakan nilai truthy/falsy secara langsung
if user.aktif?
  # ...
end

unless nilai
  # ...
end
Perbedaan ini penting ketika datang dari JavaScript atau Python. Di JavaScript, 0, "", dan [] adalah falsy. Di Python, 0, "", dan [] juga falsy. Di Ruby, hanya nil dan false yang falsy — semua nilai lain termasuk 0, "", dan [] adalah truthy. Ini sumber bug yang umum bagi developer yang baru pindah ke Ruby.

NilClass #

nil adalah satu-satunya instance dari NilClass dan mewakili ketiadaan nilai. Berbeda dari 0, false, atau ""nil secara eksplisit berarti “tidak ada nilai”.

puts nil.class     # => NilClass
puts nil.nil?      # => true
puts nil.to_i      # => 0
puts nil.to_f      # => 0.0
puts nil.to_s      # => ""  (string kosong, bukan "nil")
puts nil.to_a      # => []  (array kosong)
puts nil.inspect   # => "nil"

# nil sebagai return value default
def cari_pengguna(id)
  # jika tidak ditemukan, tidak ada return eksplisit
end

hasil = cari_pengguna(999)
puts hasil.nil?   # => true

Menangani nil dengan Aman #

# ANTI-PATTERN: akses method tanpa cek nil — rentan NoMethodError
def tampilkan_email(user)
  puts user.email.upcase   # crash jika user nil atau email nil
end

# Cara 1: cek nil eksplisit
def tampilkan_email(user)
  if user && user.email
    puts user.email.upcase
  else
    puts "Email tidak tersedia"
  end
end

# Cara 2: safe navigation operator &. (paling idiomatik)
def tampilkan_email(user)
  puts user&.email&.upcase || "Email tidak tersedia"
end

# Cara 3: nil? check
def tampilkan_email(user)
  return "User tidak ditemukan" if user.nil?
  return "Email belum diset" if user.email.nil?
  user.email.upcase
end

Range #

Range merepresentasikan urutan nilai dengan titik awal dan akhir. Ia bisa berisi Integer, Float, String, atau objek lain yang mengimplementasikan metode perbandingan.

# Dua jenis Range
inklusif  = 1..10    # mencakup 10
eksklusif = 1...10   # tidak mencakup 10 (1 sampai 9)

puts inklusif.include?(10)   # => true
puts eksklusif.include?(10)  # => false

# Konversi ke Array
puts (1..5).to_a.inspect         # => [1, 2, 3, 4, 5]
puts ('a'..'e').to_a.inspect     # => ["a", "b", "c", "d", "e"]

# Method umum Range
r = (1..100)
puts r.min          # => 1
puts r.max          # => 100
puts r.sum          # => 5050
puts r.count        # => 100
puts r.include?(50) # => true
puts r.cover?(50.5) # => true (cover? lebih cepat, tidak iterasi)

# Penggunaan praktis
angka = 75
case angka
when 90..100 then puts "A"
when 80..89  then puts "B"
when 70..79  then puts "C"
else              puts "D atau E"
end
# => "C"

# Step — range dengan langkah tertentu
(0..20).step(5) { |n| print "#{n} " }
# => 0 5 10 15 20

Konversi Antar Tipe #

Ruby menyediakan dua jenis method konversi yang berbeda perilakunya — penting untuk dipahami perbedaannya.

# Konversi "lunak" (to_i, to_f, to_s, to_a) — tidak error, menghasilkan default
"42".to_i        # => 42
"3.14".to_f      # => 3.14
"abc".to_i       # => 0  (tidak error, ambil angka yang ditemukan di awal)
"123abc".to_i    # => 123 (berhenti saat ketemu non-digit)
nil.to_i         # => 0
nil.to_s         # => ""
nil.to_a         # => []
42.to_s          # => "42"
42.to_f          # => 42.0

# Konversi "keras" (Integer(), Float(), String()) — raise error jika gagal
Integer("42")    # => 42
Integer("abc")   # => ArgumentError: invalid value for Integer()
Float("3.14")    # => 3.14
Float("abc")     # => ArgumentError
Integer(nil)     # => TypeError
# ANTI-PATTERN: to_i untuk validasi input — menyembunyikan input invalid
def proses_umur(input)
  umur = input.to_i   # "abc".to_i => 0 — seolah valid padahal tidak
  raise "Umur tidak valid" if umur <= 0
end

# BENAR: Integer() untuk konversi dengan validasi
def proses_umur(input)
  umur = Integer(input)   # raise ArgumentError jika bukan angka valid
  raise ArgumentError, "Umur harus positif" if umur <= 0
  umur
rescue ArgumentError
  raise ArgumentError, "Input umur tidak valid: #{input}"
end
MethodPerilaku saat input invalidGunakan untuk
to_iKembalikan 0Konversi yang boleh gagal secara diam-diam
to_fKembalikan 0.0Konversi yang boleh gagal secara diam-diam
to_sKembalikan ""Hampir selalu aman
Integer()Raise ArgumentErrorValidasi input dari user
Float()Raise ArgumentErrorValidasi input dari user

Duck Typing #

Ruby menggunakan pendekatan duck typing — yang penting bukan tipe objeknya, tapi apakah ia punya method yang dibutuhkan. Nama ini berasal dari idiom: “Jika ia berjalan seperti bebek dan bersuara seperti bebek, maka ia adalah bebek.”

# ANTI-PATTERN: cek tipe secara eksplisit — tidak idiomatik di Ruby
def cetak_panjang(koleksi)
  if koleksi.is_a?(Array)
    puts koleksi.length
  elsif koleksi.is_a?(String)
    puts koleksi.length
  elsif koleksi.is_a?(Hash)
    puts koleksi.length
  end
end

# BENAR: duck typing — cukup panggil method yang dibutuhkan
def cetak_panjang(koleksi)
  puts koleksi.length   # bekerja untuk Array, String, Hash, dan semua yang punya .length
end

cetak_panjang([1, 2, 3])          # => 3
cetak_panjang("halo")             # => 4
cetak_panjang({a: 1, b: 2})       # => 2

# Cek kemampuan, bukan identitas — respond_to? lebih idiomatik dari is_a?
def simpan(objek)
  if objek.respond_to?(:to_json)
    simpan_sebagai_json(objek.to_json)
  else
    raise ArgumentError, "Objek tidak bisa dikonversi ke JSON"
  end
end
flowchart TD
    A["Objek diterima sebagai argumen"] --> B{is_a? atau respond_to??}
    B --> C["is_a?(Tipe)\n— cek identitas kelas"]
    B --> D["respond_to?(:method)\n— cek kemampuan"]
    C --> E["Kaku — hanya bekerja\nuntuk kelas yang persis sama"]
    D --> F["Fleksibel — bekerja untuk\nsemua objek yang punya method itu"]
    F --> G["✓ Cara idiomatik Ruby\n(Duck Typing)"]
    E --> H["✗ Hindari kecuali benar-benar\nperlu cek tipe spesifik"]

Ringkasan #

  • Semua nilai di Ruby adalah objek — Integer, Float, String, bahkan nil dan true semuanya punya method yang bisa dipanggil.
  • Integer division membuang desimal7 / 2 menghasilkan 3, bukan 3.5. Gunakan 7.fdiv(2) atau pastikan salah satu operand Float.
  • Float tidak cocok untuk uang — gunakan BigDecimal untuk kalkulasi finansial yang butuh presisi tepat.
  • Symbol adalah singleton:nama selalu objek yang sama di memori, berbeda dari "nama" yang membuat objek baru setiap kali ditulis. Gunakan Symbol untuk key Hash dan identifier internal.
  • Hanya nil dan false yang falsy0, "", dan [] adalah truthy di Ruby, berbeda dari JavaScript dan Python.
  • nil mewakili ketiadaan nilai — bukan 0 atau "". Gunakan safe navigation &. untuk mencegah NoMethodError saat nilai mungkin nil.
  • Range punya dua bentuk.. inklusif (termasuk titik akhir), ... eksklusif (tidak termasuk titik akhir). cover? lebih cepat dari include? untuk range non-integer.
  • Konversi “keras” vs “lunak”Integer() raise error jika input invalid (bagus untuk validasi), sedangkan to_i mengembalikan 0 secara diam-diam (berbahaya untuk input dari user).
  • Duck typing lebih idiomatik dari cek tipe — gunakan respond_to?(:method) daripada is_a?(Kelas) agar kode lebih fleksibel dan generik.

← Sebelumnya: Konstanta   Berikutnya: Operator →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact