I noticed in the Lua manual that the concatenation operator is right associative. The operation itself is associative: you get the same result from ("a".."b").."c" as for "a"..("b".."c"), therefore why did Lua prefer the latter?
So I took a look at the generated bytecode and discovered the answer. Right associativity forces the operands to be all put into consecutive registers once each is evaluated. Then Lua, instead of issuing a pairwise concatenation for each pair of operands, issues a concatenation for all operands at a time. For example, in the case of "a".."b".."c", instead of concatenating "b" and "c" and generating an intermediate result "bc", and then concatenate "a" with it to obtain "abc", it does all three at a time, and therefore there's no generation of intermediate strings that would need to be garbage-collected at some point otherwise.
This can be easily verified with this program:
Code: Select all
local x
x = "a" .. "b"
x = "a" .. "b" .. "c"
x = "a" .. ("b" .. "c") -- equivalent to plain concatenation
x = ("a" .. "b") .. "c" -- bad - intermediate string generated
Code: Select all
1 [1] LOADNIL 0 0
2 [2] LOADK 1 -1 ; "a"
3 [2] LOADK 2 -2 ; "b"
4 [2] CONCAT 0 1 2
5 [3] LOADK 1 -1 ; "a"
6 [3] LOADK 2 -2 ; "b"
7 [3] LOADK 3 -3 ; "c"
8 [3] CONCAT 0 1 3
9 [4] LOADK 1 -1 ; "a"
10 [4] LOADK 2 -2 ; "b"
11 [4] LOADK 3 -3 ; "c"
12 [4] CONCAT 0 1 3
13 [5] LOADK 1 -1 ; "a"
14 [5] LOADK 2 -2 ; "b"
15 [5] CONCAT 1 1 2
16 [5] LOADK 2 -3 ; "c"
17 [5] CONCAT 0 1 2
18 [5] RETURN 0 1
Lines 2-4 correspond to x = "a".."b". Line 2 stores "a" into register 1, and line 3 stores "b" into register 2. Line 4 concatenates registers 1 to 2 and places the result in register 0 (which is the register that x is assigned to).
Lines 5-8 correspond to x = "a".."b".."c". Lines 5-7 store the constants into registers 1 to 3, and note how line 8 concatenates all three registers, storing the result into x. This way, no intermediate string is generated during concatenation.
Lines 9-12 correspond to x = "a"..("b".."c"), and are essentially identical to 5-8, thus demonstrating the right associativity of the operator.
Lines 13-17 correspond to x = ("a".."b").."c". Since we're forcing left-associativity, a concatenation must happen when both "a" and "b" are evaluated. This concatenation involves two registers, and results in the intermediate string "ab". This result is put in register 1. Then the constant "c" is loaded into register 2, and the two strings "ab" and "c" are concatenated in line 17, storing the result in register 0. This way, an intermediate string has been generated, "ab", which is somewhere in the object list and will need to be garbage collected.
I don't know if the intermediate strings that are created when implicitly calling tostring() in arguments that are not already strings, count as garbage-collectable objects or are somehow directly placed in the internal concatenation buffer without generating an object. I'd need to dig into the Lua code to find out.
tl;dr: Don't worry about generating garbage for the intermediate results of concatenation, when concatenating many pieces of a string in a single statement. The only potential cause of concern is to fill the register bank. If that happens, you can group smaller concatenations like this: (string1 .. string2 .. ... .. stringK) .. stringKplus1 .. stringKplus2 .. stringKplus3 .. ... .. stringN