Type Coercion in Lua
Type Coercion in Lua
“Type coercion” is the implicit or automatic conversion of a value from one type to another. In Lua, this is either from a string to a number or a number to a string.
Lua will automatically convert the string and number types to the correct format in order to perform calculations. For example, if you try to apply an arithmetic operation to a string, Lua will try to convert that string to a number first, otherwise, the operation will not work. If the string cannot be converted to a number, an error is raised.
During Concatenation
When the concatenation operator is used, Lua converts a number into a string. For example:
print("This is Lua version " .. 5.1 .. " we are using.")
- Output: This is Lua version 5.1 we are using.
print("Pi: " .. math.pi)
- Output: Pi: 3.1415926535898
print("Pi: " .. 3.1415927)
- Output: Pi: 3.1415927
As shown above, during coercion, we do not have full control over the formatting of the conversion. To format the number as a string as we would like we can use the string.format()
function. For example:
print(("%.3f"):format(5.1))
- Output: 5.100
- Note how there are three decimal places.
print("Lua version " .. ("%.1f"):format(5.1))
- Output: Lua version 5.1
This is an explicit conversion using a function to convert the number, rather than coercion.
During Arithmetic
Something you must remember about coercion is that it should be avoided when possible. Just because it works doesn’t mean it is good practice to use it. There’s nothing wrong with not converting a number before sending it to a function that will still accept it anyways, for instance, but try to avoid coercion when you can.
Examples
print(100 + "7")
- Output: 107
print("1000" + 234)
- Output: 1234
print(234 + "1000")
- Output: 1234
print("hello" + 234)
- Output: attempt to perform arithmetic on a string value
You can see where a string can be converted to a number, the calculation succeeds. The string “hello” cannot be converted to a number and so an error occurs. In statically typed languages (e.g. C) this would cause an error as you cannot assign a value to a variable of an incompatible type. This works in Lua because it is dynamically typed.
During Comparisons
A notable exception: comparison operators (== ~= < > <= >=) do not coerce their arguments. The (in)equality operators consider a number to be not equal to its string representation (or any non-number type in fact). Ordered comparison operators throw an error when you feed them different types:
print(100 == "100")
- Output: false
print(100 ~ "hello")
- Output: true
print(100 ~ {})
- Output: true
print(100 == tonumber("100"))
- Output: true
print(100 < "100")
- Output: attempt to compare number with string
Coercion of Other Types
Coercion does not only exist for numbers and strings. There are also other cases of coercion that apply in Roblox.
Enums
One example is enums. When you use a string or a number where an enum or a number is expected, it is coerced to an enum.
Here are three examples that all do the same things, they all create a Part and make it Concrete:
local p1 = Instance.new(**Part**) p1.Material = 816 p1.Parent = workspace local p2 = Instance.new(**Part**) p2.Material = **Concrete** p2.Parent = workspace local p3 = Instance.new(**Part**) p3.Material = Enum.Material.Concrete p3.Parent = workspace
TimeOfDay
Another example of coercion is with the TimeOfDay property of the Lighting. This property sets the current time in the server, which defines whether it is night, day, or any other time. The TimeOfDay property is a string, but, if you send it a number as an argument, it will still work.
Here are two examples. One uses a number, and one uses a string. Both do the same thing:
game.Lighting.TimeOfDay = 5 print(game.Lighting.TimeOfDay)
Which outputs “05:00:00”
game.Lighting.TimeOfDay = "05:00:00" print(game.Lighting.TimeOfDay)
Which outputs “05:00:00”