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".length โ†’ 4, "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 / 3 โ†’ 3.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.