Overview
Array literals in Ruby provide a concise syntax for creating arrays using square brackets. Ruby supports multiple array literal syntaxes beyond the standard [1, 2, 3]
format, including word arrays, symbol arrays, and percent notation. The array literal syntax creates new Array objects and supports various element types, nested structures, and dynamic content.
Ruby evaluates expressions within array literals at creation time, making them distinct from array construction methods. Array literals support splat operators, ranges, and other Ruby constructs, enabling flexible array initialization patterns.
# Standard array literal
numbers = [1, 2, 3, 4, 5]
# Mixed types
mixed = [1, "hello", :symbol, true]
# Nested arrays
nested = [[1, 2], [3, 4], [5, 6]]
The Array class implements array literals through the []
method, supporting both indexed access and literal creation. Ruby parses array literals at compile time, optimizing memory allocation and element initialization.
Basic Usage
Standard array literals use square brackets with comma-separated elements. Ruby creates a new Array instance containing the specified elements in order.
# Empty array
empty = []
# Single element
single = ["hello"]
# Multiple elements
fruits = ["apple", "banana", "orange"]
# Numeric arrays
primes = [2, 3, 5, 7, 11, 13]
Word arrays using %w
provide clean syntax for string arrays without quotes. The delimiter following %w
determines the array boundaries, with matching delimiters supported.
# Word array with spaces
colors = %w[red green blue yellow]
# => ["red", "green", "blue", "yellow"]
# Custom delimiter
animals = %w(cat dog bird fish)
# => ["cat", "dog", "bird", "fish"]
# With braces
languages = %w{ruby python javascript}
# => ["ruby", "python", "javascript"]
Symbol arrays using %i
create arrays of symbols without individual colon prefixes. This syntax mirrors word arrays but produces Symbol objects instead of strings.
# Symbol array
statuses = %i[pending approved rejected]
# => [:pending, :approved, :rejected]
# Mixed case symbols
actions = %i[createUser deleteUser updateUserProfile]
# => [:createUser, :deleteUser, :updateUserProfile]
Dynamic content evaluation occurs within array literals, executing expressions and method calls during array creation.
# Method calls in array literals
values = [Time.now, rand(100), "user_#{rand(1000)}"]
# Variable interpolation
name = "John"
data = [name.upcase, name.length, name.reverse]
# => ["JOHN", 4, "nhoJ"]
# Range expansion
range_array = [1, 2, *(5..8), 10]
# => [1, 2, 5, 6, 7, 8, 10]
Advanced Usage
Splat operators within array literals enable complex array composition and flattening. The *
operator expands arrays and other enumerable objects into individual elements.
# Array concatenation with splat
first_half = [1, 2, 3]
second_half = [4, 5, 6]
complete = [*first_half, *second_half]
# => [1, 2, 3, 4, 5, 6]
# Conditional inclusion
include_extra = true
base_array = [1, 2, 3]
result = [*base_array, *(include_extra ? [4, 5] : [])]
# Hash to array conversion
person = { name: "Alice", age: 30 }
person_array = [*person]
# => [[:name, "Alice"], [:age, 30]]
Double splat operators (**
) work with hash-like objects, though less commonly used in array literals. They convert hash arguments into key-value pairs.
# Double splat with array-compatible objects
def create_array(**kwargs)
[**kwargs]
end
result = create_array(a: 1, b: 2)
# => [[:a, 1], [:b, 2]]
Block evaluation within array literals executes during array creation, allowing computed elements based on runtime conditions.
# Conditional array building
user_permissions = %w[read write]
admin_mode = true
permissions = [
*user_permissions,
*(admin_mode ? %w[delete admin] : [])
]
# => ["read", "write", "delete", "admin"]
# Complex nested structures
matrix = [
[*(1..3)],
[*(4..6)],
[*(7..9)]
]
# => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Method chaining with array literals creates fluent interfaces for array manipulation. Ruby evaluates the literal first, then applies subsequent method calls.
# Immediate processing
processed = [1, 2, 3, 4, 5].select(&:odd?).map { |n| n * 2 }
# => [2, 6, 10]
# Combining literals with enumerable methods
coordinates = [
[0, 0], [1, 1], [2, 2]
].map { |x, y| { x: x, y: y } }
# => [{:x=>0, :y=>0}, {:x=>1, :y=>1}, {:x=>2, :y=>2}]
# Nested array processing
nested_data = [
%w[apple fruit],
%w[carrot vegetable],
%w[salmon fish]
].to_h
# => {"apple"=>"fruit", "carrot"=>"vegetable", "salmon"=>"fish"}
Common Pitfalls
Array literal evaluation timing can cause unexpected behavior when expressions have side effects or depend on mutable state. Ruby evaluates all expressions within the literal at creation time.
# Problematic: shared mutable objects
counter = 0
arrays = [[counter += 1], [counter += 1], [counter += 1]]
# => [[1], [2], [3]]
# counter is now 3
# Problem: shared object references
template = []
nested = [template, template, template]
nested[0] << "modified"
# All sub-arrays affected: [["modified"], ["modified"], ["modified"]]
# Solution: create separate objects
nested_safe = [[], [], []]
nested_safe[0] << "modified"
# Only first sub-array affected: [["modified"], [], []]
Percent notation limitations restrict the characters available as delimiters and require careful escaping. Nested delimiters must be escaped or balanced.
# Problematic: unbalanced delimiters in %w
# %w[words with [brackets] inside] # Syntax error
# Solution: escape or use different delimiter
words_escaped = %w[words with \[brackets\] inside]
# => ["words", "with", "[brackets]", "inside"]
# Alternative delimiter
words_parens = %w(words with [brackets] inside)
# => ["words", "with", "[brackets]", "inside"]
Variable interpolation differences between %w
and %W
arrays create subtle bugs. Lowercase %w
treats content literally, while uppercase %W
enables interpolation.
name = "John"
# No interpolation with %w
literal = %w[hello #{name} world]
# => ["hello", "\#{name}", "world"]
# Interpolation with %W
interpolated = %W[hello #{name} world]
# => ["hello", "John", "world"]
# Mixed interpolation gotcha
mixed = %W[#{name} #{undefined_variable}]
# => NameError: undefined local variable or method
Splat operator precedence can produce unexpected results when combined with other operators or method calls. Ruby evaluates splatted expressions before array creation.
# Precedence confusion
array_a = [1, 2]
array_b = [3, 4]
# Unexpected precedence
result = [*array_a + array_b] # array_a + array_b evaluated first
# => [1, 2, 3, 4] (single flattened array)
# Intended behavior
result_correct = [*array_a, *array_b]
# => [1, 2, 3, 4] (same result, clearer intent)
# Complex precedence issues
multiplier = 2
problematic = [*(1..3).map { |n| n * multiplier }]
# Works, but precedence unclear
clearer = [*((1..3).map { |n| n * multiplier })]
# Same result, explicit precedence
Reference sharing in nested array literals creates aliasing issues where modifications affect multiple array elements unexpectedly.
# Shared reference problem
shared_array = ["shared"]
container = [shared_array, shared_array, shared_array]
container[0] << "modified"
# All elements affected: [["shared", "modified"], ["shared", "modified"], ["shared", "modified"]]
# Detection technique
container[0].object_id == container[1].object_id # => true
# Prevention with Array.new
safe_container = Array.new(3) { ["separate"] }
safe_container[0] << "modified"
# Only first affected: [["separate", "modified"], ["separate"], ["separate"]]
safe_container[0].object_id == safe_container[1].object_id # => false
Reference
Array Literal Syntax
Syntax | Description | Example | Result |
---|---|---|---|
[] |
Empty array literal | empty = [] |
[] |
[a, b, c] |
Standard element list | [1, 2, 3] |
[1, 2, 3] |
%w[...] |
Word array (strings) | %w[a b c] |
["a", "b", "c"] |
%W[...] |
Word array with interpolation | %W[#{var} b] |
["value", "b"] |
%i[...] |
Symbol array | %i[a b c] |
[:a, :b, :c] |
%I[...] |
Symbol array with interpolation | %I[#{var} b] |
[:value, :b] |
Splat Operations
Operation | Description | Example | Result |
---|---|---|---|
*array |
Array expansion | [1, *[2, 3], 4] |
[1, 2, 3, 4] |
*range |
Range expansion | [1, *(5..7), 9] |
[1, 5, 6, 7, 9] |
*string |
String character expansion | [*"abc"] |
["a", "b", "c"] |
**hash |
Hash to key-value pairs | [**{a: 1}] |
[[:a, 1]] |
Percent Notation Delimiters
Delimiter Pair | Valid Usage | Example |
---|---|---|
[] |
%w[...] , %i[...] |
%w[red blue green] |
() |
%w(...) , %i(...) |
%w(cat dog bird) |
{} |
%w{...} , %i{...} |
%w{ruby python java} |
<> |
%w<...> , %i<...> |
%w<north south east west> |
// |
%w/.../ , %i/.../ |
%w/one two three/ |
|| |
%w|...| , %i|...| |
%w|alpha beta gamma| |
Common Array Literal Patterns
Pattern | Code Example | Use Case |
---|---|---|
Empty with type hint | strings = String.new.split |
Type-safe empty arrays |
Conditional inclusion | [base, *(condition ? extra : [])] |
Optional elements |
Range-based | [(1..5).to_a, (6..10).to_a].flatten |
Numeric sequences |
Nested structure | [[*row1], [*row2]] |
Matrix/grid data |
Mixed splat | [scalar, *array, **hash.to_a] |
Complex composition |
Performance Characteristics
Operation | Time Complexity | Memory | Notes |
---|---|---|---|
Literal creation [a,b,c] |
O(n) | O(n) | Linear with element count |
Splat expansion [*array] |
O(n) | O(n) | Creates new array |
Percent notation %w[...] |
O(n) | O(n) | Compile-time optimization |
Nested literals [[],[]] |
O(n*m) | O(n*m) | Multiplicative nesting |
Error Conditions
Error Type | Trigger | Example |
---|---|---|
SyntaxError |
Unbalanced delimiters | %w[unclosed |
NameError |
Undefined variable in interpolation | %W[#{undefined}] |
ArgumentError |
Invalid splat target | [*non_enumerable] |
NoMethodError |
Missing method in expression | [object.missing_method] |