Why do two strings separated by space concatenate in Ruby?
Asked Answered
M

2

46

Why does this work in Ruby:

"foo" "bar"
# => "foobar"

I'm unsure as to why the strings were concatenated instead of a syntax error being given.

I'm curious as to whether or not this is expected behavior and whether or not it's something the parser is responsible for wrangling (two strings without operators is considered a single string) or the language definition itself is specifying this behavior (implicit concat).

Mcgrath answered 22/5, 2014 at 15:31 Comment(2)
Same thing happens in PythonBoughton
Interesting. As JKillian stated, it must be related to the C background both languages share.Mcgrath
T
38

Implementation details can be found in parse.y file in Ruby source code. Specifically, here.

A Ruby string is either a tCHAR (e.g. ?q), a string1 (e.g. "q", 'q', or %q{q}), or a recursive definition of the concatenation of string1 and string itself, which results in string expressions like "foo" "bar", 'foo' "bar" or ?f "oo" 'bar' being concatenated.

Tisza answered 22/5, 2014 at 15:54 Comment(3)
Kudos for that find. Does seem to be a parser-related "feature" then. Accepting this one for the justification here rather than a set of links.Mcgrath
"a" 'b' %q{c} #=> NameError: uninitialized constant q Why does this lead to an error then?Harpoon
@IngridMorstrad Because the % is considered a modulus operator, not part of a string literal. Being a binary operator, the expression you mentioned is parsed as 'ab' % (q{c}), with the block {c} passed to q which doesn't exist (presumably), hence the error.Tisza
I
53

In C and C++, string literals next to each other are concatenated. As these languages influenced Ruby, I'd guess it inherits from there.

And it is documented in Ruby now: see this answer and this page in the Ruby repo which states:

Adjacent string literals are automatically concatenated by the interpreter:

"con" "cat" "en" "at" "ion" #=> "concatenation"
"This string contains "\
"no newlines."              #=> "This string contains no newlines."

Any combination of adjacent single-quote, double-quote, percent strings will be concatenated as long as a percent-string is not last.

%q{a} 'b' "c" #=> "abc"
"a" 'b' %q{c} #=> NameError: uninitialized constant q
Investigation answered 22/5, 2014 at 15:41 Comment(3)
+1 for referencing the docs, though I think the important info should probably be added to the answer. I couldn't figure out good terms to search for "string literal juxtaposition". Thanks.Mcgrath
This feature exists in many languages (presumably all borrowing it from C) and is useful when wrapping long strings over multiple lines. It is also different from simply concatenating the strings (with +, & or whatever the language uses) as it happens at "compile" time and it's therefore still a string literal, and not an expression evaluated at run-time.Aldose
Actually, the “as long as a percent-string is not last” does not reflect the real behavior. From what I tried, the concatenation throws a syntax error, unexpected tSTRING_BEG, expecting end-of-input when the percent-string is not first, but also not last, like "a" %q{b} "c".Dicky
T
38

Implementation details can be found in parse.y file in Ruby source code. Specifically, here.

A Ruby string is either a tCHAR (e.g. ?q), a string1 (e.g. "q", 'q', or %q{q}), or a recursive definition of the concatenation of string1 and string itself, which results in string expressions like "foo" "bar", 'foo' "bar" or ?f "oo" 'bar' being concatenated.

Tisza answered 22/5, 2014 at 15:54 Comment(3)
Kudos for that find. Does seem to be a parser-related "feature" then. Accepting this one for the justification here rather than a set of links.Mcgrath
"a" 'b' %q{c} #=> NameError: uninitialized constant q Why does this lead to an error then?Harpoon
@IngridMorstrad Because the % is considered a modulus operator, not part of a string literal. Being a binary operator, the expression you mentioned is parsed as 'ab' % (q{c}), with the block {c} passed to q which doesn't exist (presumably), hence the error.Tisza

© 2022 - 2024 — McMap. All rights reserved.