luaguides

tostring

tostring(v)

tostring converts any Lua value into a human-readable string. Numbers, booleans, and nil all convert predictably. Tables, functions, threads, and userdata get a pointer address like table: 0x7f8a3c102030 — the object’s memory location in the C implementation. The original value is never modified.

Signature

tostring(v)

Parameters:

  • v — any Lua value

Returns: string

Basic Types

tostring(42)        --> "42"
tostring(3.14)      --> "3.14"
tostring(-100)       --> "-100"
tostring(true)       --> "true"
tostring(false)      --> "false"
tostring(nil)        --> "nil"

Numbers are formatted as you’d write them in source. No rounding, no trailing zeros for integers.

Complex Types

tostring({})           --> "table: 0x7f8a3c102030"
tostring(print)        --> "function: 0x7f8a3c102100"
tostring(coroutine.create(function() end))
                      --> "thread: 0x7f8a3c102200"

The hex address is the object’s memory location. Two identical-looking tables always produce different addresses — they are different objects.

Why You Need It

Lua’s .. concatenation operator requires strings on both sides. Without tostring, converting a number or boolean for concatenation raises an error:

"score: " .. 42         --> error: attempt to concatenate string with number
"score: " .. tostring(42)  --> "score: 42"

This is the main reason tostring exists — enabling string building with non-string values.

Practical Patterns

Debug Logging

function dump(value)
  print(tostring(value))
end

dump(42)        --> 42
dump({a = 1})   --> table: 0x...
dump(nil)       --> nil

tostring on a table only shows its address, not contents. For table contents, you need a custom pretty-printer.

Safe Concatenation

function label(key, value)
  return key .. ":" .. tostring(value)
end

label("count", 5)     --> "count:5"
label("name", nil)   --> "name:nil"
label("active", true) --> "active:true"

Wrapping values in tostring lets you build strings without type-checking every argument.

Default Values

function greet(name)
  name = tostring(name)
  if name == "" or name == "nil" then
    return "Hello, World"
  end
  return "Hello, " .. name
end

greet("Alice")   --> "Hello, Alice"
greet(nil)       --> "Hello, nil"
greet("")        --> "Hello, World"

tostring vs String Concatenation

Lua 5.3+ handles "" .. 42 implicitly — the left string operand triggers conversion. But if you try 42 .. "", Lua evaluates the left side first as a number and the .. operator can’t start with a number, so use tostring(42) to be explicit:

"" .. 42          --> "42" (works)
tostring(42) .. "" --> "42" (explicit and clear)

__tostring Metamethod

Tables can define a custom string representation via the __tostring metamethod:

local point = setmetatable({x = 1, y = 2}, {
  __tostring = function(self)
    return string.format("(%d, %d)", self.x, self.y)
  end
})
print(tostring(point))   --> "(1, 2)"

Note: tostring in standard Lua does not call __tostring. This works because print calls tostring internally which can use __name in some contexts. For cross-version reliability, use a dedicated __tostring method and call it explicitly rather than relying on print/tostring to pick it up.

See Also