These 2 scripts microbenchmark 2 possible implementations of str.StartsWith:
string.find (current implementation):
local _ = string.sub -- just to normalize the bytecode size comparison
_ = string.find -- just to normalize the bytecode size comparison
local t = os.clock()
for i = 1, 1700 do
local l = ("hello world"):find("hello ") == 1
end
t = os.clock() - t
print(t, ll.GetUsedMemory()) -- 0.0002 2471
string.sub (my recommended implementation):
local _ = string.sub -- just to normalize the bytecode size comparison
_ = string.find -- just to normalize the bytecode size comparison
local t = os.clock()
for i = 1, 3200 do
local l = string.sub("hello world", 1, #"hello ") == "hello "
end
t = os.clock() - t
print(t, ll.GetUsedMemory()) -- 0.0001 2472
As you can see from the above benchmark, the string.sub implementation runs about twice as fast as the string.find implementation, while using only 1 more byte of bytecode. It can fiit twice as many calls into a single SL timeslice as the other. This is because
- When
# operates on a literal string, or a constant, the operator is constant-folded away into a number literal by the compiler
string.sub is a luau fastcall, but string.find is not.
When the argument is not a constant, the current string.find implementation is faster than string.sub. I've no idea if the transpiler can differentiate between a literal/constant and a non-constant. If not, disregard this suggestion.
Tested on Aditi Luau 2026-05-12.25767303752
These 2 scripts microbenchmark 2 possible implementations of
str.StartsWith:string.find(current implementation):string.sub(my recommended implementation):As you can see from the above benchmark, the
string.subimplementation runs about twice as fast as thestring.findimplementation, while using only 1 more byte of bytecode. It can fiit twice as many calls into a single SL timeslice as the other. This is because#operates on a literal string, or a constant, the operator is constant-folded away into a number literal by the compilerstring.subis a luau fastcall, butstring.findis not.When the argument is not a constant, the current
string.findimplementation is faster thanstring.sub. I've no idea if the transpiler can differentiate between a literal/constant and a non-constant. If not, disregard this suggestion.Tested on Aditi Luau 2026-05-12.25767303752