Symbol và String trong Ruby: semantics trước micro-benchmark

String biểu diễn text mutable; Symbol biểu diễn identifier/name immutable.

1
2
"status" == "status" # => true
:status.equal?(:status) # => true

Dùng Symbol khi

  • key nội bộ ổn định;
  • tên method, state, option;
  • value thuộc tập identifier nhỏ.
1
2
user.public_send(:name)
{ status: :active }

Dùng String khi

  • text từ user/network/file;
  • cần encoding, nối, replace, format;
  • số lượng value động/lớn.
1
name = params[:name].to_s

Memory myth

Ruby hiện đại garbage-collect dynamic symbols, nên câu “symbol không bao giờ được GC” không còn đúng chung. Dù vậy, convert input tùy ý thành symbol vẫn không cần thiết và có thể tăng memory:

1
2
# Không nên nếu key không được kiểm soát
params.keys.map(&:to_sym)

Allowlist key hoặc giữ string.

Performance

Symbol comparison có thể rẻ vì identity ổn định, nhưng application performance hiếm khi được cứu bởi đổi vài hash key. Database, network và allocation lớn thường đáng đo trước.

Chọn theo semantics:

  • identifier → Symbol;
  • nội dung → String.

Nếu phải giải thích value này là text hay label, loại dữ liệu nên trả lời trước benchmark. Micro-optimization khi domain chưa rõ là chạy rất nhanh về sai hướng.