Variables & Data Types

Ruby Fundamentals — Variables & Data Types
Ruby Fundamentals
Course 1 · Chapter 2 · Variables & Data Types

📦 Variables & Data Types

Chapter 1 showed that every Ruby value is an object. This chapter covers the everyday types you'll build those objects out of — strings, numbers, arrays, and hashes — plus two ideas with no clean PHP or Python equivalent: symbols, and how nil actually behaves in a boolean context.

✏️ Variables — No Declaration Keyword

Ruby variables need no declaration keyword and no sigil — just assign a name and Ruby infers the type from the value, exactly like Python. This is a step further than PHP, which requires the $ sigil on every variable reference, not just at declaration:

age = 33 # no $ sigil, no let/var/val keyword name = "Philip" is_ready = true # snake_case is Ruby's naming convention, like Python

Ruby variable names use snake_case by convention (like Python; PHP's convention varies between snake_case and camelCase depending on the codebase). Variable names are entirely lowercase by convention too — a name starting with a capital letter means something different in Ruby, as you'll see once classes and constants show up in later chapters.

🔤 Strings — Single vs Double Quotes Actually Matter

Both single and double quotes create strings, but unlike PHP (where the same distinction exists) they aren't interchangeable — only double quotes support interpolation and escape sequences:

name = "Philip" puts "Hello, #{name}!" # Hello, Philip! -- double quotes interpolate puts 'Hello, #{name}!' # Hello, #{name}! -- single quotes are literal puts "Line one\nLine two" # \n becomes a real newline in double quotes puts 'Line one\nLine two' # \n stays as literal backslash-n in single quotes

String Interpolation: PHP vs Python vs Ruby

PHPPythonRuby
Interpolating syntax"Hi $name"f"Hi {name}""Hi #{name}"
Requires special prefix?NoYes — f-stringNo — plain double quotes
Non-interpolating quote'...' (literal)Any plain string'...' (literal)

Common string methods: "ruby".upcase"RUBY", "RUBY".downcase"ruby", "ruby".length4, "ruby".reverse"ybur", and concatenation with + or repetition with * ("ab" * 3"ababab").

🔢 Numbers — Watch Out for Integer Division

10 / 3 # => 3 -- Integer / Integer stays an Integer, truncated 10.0 / 3 # => 3.3333333333333335 -- a Float on either side forces Float division 10.fdiv(3) # => 3.3333333333333335 -- explicit float division method
⚠ This gotcha is a real trap coming from PHP or Python 3

In PHP, 10 / 3 automatically produces a float (3.3333...) — there's no separate integer-division operator by default. In Python 3, / is always float division (10 / 33.333...), and you'd deliberately reach for // to truncate. Ruby does the opposite of both: plain / between two integers truncates, silently, with no warning. Forgetting this is one of the most common early Ruby bugs for anyone coming from either language.

🔖 Symbols — The New Concept

A symbol is a lightweight, immutable identifier written with a leading colon: :name, :status, :pending. Neither PHP nor Python has a direct equivalent — the closest PHP gets is a bare string constant, and the closest Python gets is an enum member, but neither carries Ruby's specific guarantee: every instance of the same symbol in a running program is the exact same object in memory.

:pending.object_id == :pending.object_id # => true -- always the same object "pending".object_id == "pending".object_id # => false -- two different String objects

Why symbols exist

Because a symbol is always the same object, comparing two symbols for equality is a fast identity check rather than a character-by-character string comparison. That makes symbols the natural choice for things that name something — hash keys, method names, status values — rather than for text that gets displayed or manipulated.

Symbols vs strings, in practice

Use a symbol (:active) when the value is really an internal label or identifier. Use a string ("active") when it's actual text — something you'll display, concatenate, or manipulate character by character. This distinction shows up constantly once hashes are in play, just below.

📚 Arrays

fruits = ["apple", "banana", "cherry"] fruits[0] # => "apple" -- zero-indexed, same as PHP/Python fruits[-1] # => "cherry" -- negative indexing, same as Python (PHP has no native equivalent) fruits.length # => 3 fruits << "date" # append -- equivalent to fruits.push("date") fruits.first # => "apple" fruits.last # => "date"

Ruby arrays are ordered, can hold mixed types in the same array (like PHP and Python lists), and the << "shovel" operator for appending is Ruby-specific — PHP uses $arr[] = $value, Python uses .append(value).

🗝️ Hashes

A hash is Ruby's key-value structure — directly comparable to a PHP associative array or a Python dict. Modern Ruby code almost always uses symbol keys with a shorthand syntax:

# Modern shorthand (symbol keys) -- the style you'll see most often person = { name: "Philip", age: 33 } person[:name] # => "Philip" # Old "hashrocket" syntax -- still required for non-symbol keys, like strings scores = { "Philip" => 95, "Alex" => 88 } scores["Philip"] # => 95

Key-Value Structures: PHP vs Python vs Ruby

PHPPythonRuby
Literal syntax["name" => "Philip"]{"name": "Philip"}{ name: "Philip" }
Read a value$arr["name"]d["name"]hash[:name]
Arrays and mapsSame type (associative array)Separate: list vs dictSeparate: Array vs Hash

🕳️ nil — Ruby's "Nothing"

nil is Ruby's equivalent of PHP's null or Python's None — it represents the absence of a value. The important, easy-to-miss detail: in a boolean context, Ruby treats only two values as falsy — nil and false. Everything else, including 0 and "" (empty string), is truthy.

if 0 puts "0 is truthy in Ruby!" # this DOES print end value = nil value.nil? # => true -- the idiomatic way to check for nil
⚠ 0 is truthy — a real difference from PHP and Python

PHP treats 0, "0", and "" as falsy in a boolean context. Python treats 0, 0.0, and empty collections/strings as falsy too. Ruby treats only nil and false as falsy — 0 and "" are both truthy. An if 0 check that would skip a block in PHP or Python will run it in Ruby.

💻 Coding Challenges

Challenge 1: Interpolation vs Concatenation

Create variables for a product name (string) and a price (float). Build the same sentence two ways: once using string interpolation with double quotes, and once using + concatenation (you'll need .to_s on the price). Print both and compare how much more readable the interpolated version is.

Goal: Get comfortable with #{ } interpolation as the default, idiomatic choice.

→ Solution

Challenge 2: Symbols Are Identical Objects

In irb, create the symbol :status twice and compare their .object_id — confirm they match. Then create the string "status" twice and compare those .object_ids — confirm they don't match. Write one sentence explaining why this matters for hash keys.

Goal: Directly observe symbols' defining property rather than just reading about it.

→ Solution

Challenge 3: An Array of Hashes

Build an array containing three hashes, each with symbol keys :name and :age, representing three people. Loop over the array with .each and print a sentence for each person using string interpolation to pull values out of the hash.

Goal: Combine arrays, hashes, and symbol keys the way they'll actually be used together in real Ruby code.

→ Solution

💎 A Rule of Thumb for Symbols vs Strings

If you're ever unsure whether something should be a symbol or a string, ask: "will this value ever be displayed to a user, or manipulated as text?" If yes, it's a string. If it's really just a label your own code uses internally — a hash key, a status, a type name — reach for a symbol. This one habit will make your hashes and method calls look like idiomatic Ruby rather than PHP or Python translated line-by-line.

🎯 What's Next

Next chapter: Control Flow — if/unless, case/when, loops (while, until, for, each), and what it means for Ruby to be expression-oriented — where even an if statement returns a value you can assign.