Interpolation vs. concatenation
Two ways to build the same string
name = "Ada"
age = 29
"Name: " + name + ", age: " + age
Run that last line and Ruby raises TypeError: no implicit conversion of Integer into String. + on strings needs both sides to be strings already, and age is an Integer. You'd have to write age.to_s by hand to make the line work. Interpolation avoids the problem:
"Name: #{name}, age: #{age}"
# "Name: Ada, age: 29"
There's no conversion to write, no error and no + chain to keep track of. #{} doesn't care what type is inside it. Whatever sits between the braces is evaluated as a Ruby expression, converted with .to_s and dropped into the string in place of the braces.
The .to_s call is real
"Converted with .to_s" is no simplification; it's the method interpolation calls. Give a class its own to_s and interpolation uses it:
class Money
def to_s
"MONEY"
end
end
"value: #{Money.new}"
# "value: MONEY"
Ruby didn't inspect the object, guess a format or raise an error over an unfamiliar class. It called .to_s on whatever Money.new returned, as it would on an Integer, an Array or nil (whose to_s returns ""). Interpolation is method dispatch with a compact syntax.
Single quotes don't interpolate
name = "Ada"
'Name: #{name}'
# "Name: #{name}"
The output is the literal text #{name}, braces and all, not "Name: Ada". Single-quoted strings treat #{} as ordinary characters. It's a common beginner bug: switching to single quotes for a string that needs a variable inside, then staring at output that looks like a template that forgot to render. If a string needs #{} to work, it has to be double-quoted (or a heredoc, covered in lesson 4).
Concatenation has its own traps
+ isn't the only way to build a string from pieces. << (the "shovel" operator) appends to a string in place, changing the original object instead of building a new one:
s = "a"
s2 = s
s << "b"
s2
# "ab" — s2 changed too, because s and s2 point at the same object
That's a real footgun. Two variables that look independent share one mutable string, and appending through either one changes what the other sees. += mutates nothing: it builds a new string and points the variable at it, leaving whatever s2 pointed at alone. Frozen strings make the danger concrete. "x".freeze << "y" raises FrozenError, because << needs to modify the object and a frozen one refuses.
Interpolation avoids this whole category of bug. "Name: #{name}, age: #{age}" always produces one new string. There's no shared mutable buffer, no +/<< distinction to get right and no accidental aliasing.
Why interpolation usually wins
Concatenation makes you turn every piece into a string first, by hand, with the right operator, in the right order. Interpolation reads like the sentence you're building, with the moving parts marked inline. For anything beyond two fixed strings glued together, it's shorter and safer. There's no TypeError from a stray Integer, no accidental mutation from the wrong operator and no hunting for a missing +.
Key takeaways
+needs both operands to be strings already; interpolation converts anything to a string by calling.to_s.#{}works only inside double-quoted strings (and heredocs); single quotes treat it as literal text.<<changes a string in place and can cause aliasing bugs when two variables share one object;+=and interpolation both build new strings instead.- Interpolation is the default way to combine strings and other values in modern Ruby; use
+/<<mainly when you're building or changing a buffer on purpose.
Keep going with lesson 2
Calling methods inside interpolation
Shows that #{} evaluates full expressions and when logic should move into a named variable first.
A free account also gives you the quizzes, your progress and notes, and the discussion.