A Quick Brown Fox - Lua Basics - Concatenation

Everyones learning abilities are different, juggling these is not an easy task, specially when some have to spell their names and program. Anyways that is hardly a barrier, what if you wanted to concatenate a table with values?
You could find various ways to do things, but the simplest of the solutions are found in the simplicity of what is available than to re-invent the wheel.

If a user wants to concatenate several strings, the concatenation operator in lua which is the .. (double dots) can be used. However if you wanted to concatenate a table and instead of joining them with a space, have them one on each line, then the easiest way is to use the table.concat method available.

so you can fire up Lua and test the following code
 local theTable = {"A", "Quick", "Brown", "Fox"}

 local function printConcat(thisTable)
  print(table.concat(thisTable,"\n"))
 end

 printConcat(theTable)

There is something that all of us learn everyday... and it is all in these subtle differences in our methodology that make the difference.

Advance Analysis

If we look at the bytecode and see how the above code compiles, we can see

; x86 standard (32-bit, little endian, doubles)

; function [0] definition (level 1)
; 0 upvalues, 0 params, 5 stacks
.function  0 0 2 5
.local  "theTable"  ; 0
.local  "printConcat"  ; 1
.const  "printConcat"  ; 0
.const  "theTable"  ; 1
.const  "A"  ; 2
.const  "Quick"  ; 3
.const  "Brown"  ; 4
.const  "Fox"  ; 5

; function [0] definition (level 2)
; 0 upvalues, 1 params, 5 stacks
.function  0 1 0 5
.local  "thisTable"  ; 0
.const  "print"  ; 0
.const  "table"  ; 1
.const  "concat"  ; 2
.const  "\n"  ; 3
[1] getglobal  1   0        ; print
[2] getglobal  2   1        ; table
[3] gettable   2   2   258  ; "concat"
[4] move       3   0      
[5] loadk      4   3        ; "\n"
[6] call       2   3   0  
[7] call       1   0   1  
[8] return     0   1      
; end of function

[01] getglobal  0   0        ; printConcat
[02] getglobal  1   1        ; theTable
[03] call       0   2   1  
[04] newtable   0   4   0    ; array=4, hash=0
[05] loadk      1   2        ; "A"
[06] loadk      2   3        ; "Quick"
[07] loadk      3   4        ; "Brown"
[08] loadk      4   5        ; "Fox"
[09] setlist    0   4   1    ; index 1 to 4
[10] closure    1   0        ; 0 upvalues
[11] move       2   1      
[12] move       3   0      
[13] call       2   2   1  
[14] return     0   1      
; end of function

If we were to instead use a for loop and interate like so

 local theTable = {"A", "Quick", "Brown", "Fox"}  

 local function printConcat(thisTable) 
   local i
   for i=1,#thisTable do
    print(thisTable[i] .. "\n")
   end
 end 

 printConcat(theTable)

However if it was upto me, I would not try to concatenate the array element and the newline character, instead use the , which is much safer if the element in the array is a non string or nil (for some strange reason)

This code would look like
; x86 standard (32-bit, little endian, doubles)

; function [0] definition (level 1)
; 0 upvalues, 0 params, 5 stacks
.function  0 0 2 5
.local  "theTable"  ; 0
.local  "printConcat"  ; 1
.const  "A"  ; 0
.const  "Quick"  ; 1
.const  "Brown"  ; 2
.const  "Fox"  ; 3

; function [0] definition (level 2)
; 0 upvalues, 1 params, 9 stacks
.function  0 1 0 9
.local  "thisTable"  ; 0
.local  "i"  ; 1
.local  "(for index)"  ; 2
.local  "(for limit)"  ; 3
.local  "(for step)"  ; 4
.local  "i"  ; 5
.const  1  ; 0
.const  "print"  ; 1
.const  "\n"  ; 2
[01] loadk      2   0        ; 1
[02] len        3   0      
[03] loadk      4   0        ; 1
[04] forprep    2   5        ; to [10]
[05] getglobal  6   1        ; print
[06] gettable   7   0   5  
[07] loadk      8   2        ; "\n"
[08] concat     7   7   8  
[09] call       6   2   1  
[10] forloop    2   -6       ; to [5] if loop
[11] return     0   1      
; end of function

[01] newtable   0   4   0    ; array=4, hash=0
[02] loadk      1   0        ; "A"
[03] loadk      2   1        ; "Quick"
[04] loadk      3   2        ; "Brown"
[05] loadk      4   3        ; "Fox"
[06] setlist    0   4   1    ; index 1 to 4
[07] closure    1   0        ; 0 upvalues
[08] move       2   1      
[09] move       3   0      
[10] call       2   2   1  
[11] return     0   1      
; end of function

Note the differences between the bytecode of the two samples, there are more instructions and stackspace required in the second sample. So when developers ask for that extra little optimization, it is better to keep that in mind when you create functions.

Comments

Popular Posts