"trick" with datatype functions, which will ruin your code

Hello guys! Did you know, that Roblox libraries, like string, table and others are metatables?
I think nope. Now you know.
And, do you know that if function uses : symbol, it passes first argument as itself? If you know metatables then you know this too.

But why I started with this 2 statements? They lead me to conclusion that we can type not long library name, and instead already pass our datatype with : symbol!
But it’s important to note that this work NOT always, and it will make your code slower by 10-20%
In some cases you can do this:

local RandomText = "Hello, I'm 34124"
print(RandomText:match("%d+"))

Instead of

local RandomText = "Hello, I'm 34124"
print(string.match(RandomText, "%d+"))

If you don’t want to make variable, put brackets around datatype:

print(("Hello, I'm 34124"):match("%d+"))

That’s all!
Initially I thought that this will be good method to not write string and other datatypes constantly, but it has much worse outcomes, thanks to @BackspaceRGB for pointing that out!

8 Likes

like string, bit32, buffer and others are metatables?

No, numbers don’t have bit32 methods and buffers don’t have methods either.

4 Likes

Hm, yes. I tried this methods not on all datatypes before posting this. My mistake, sorry.

3 Likes

If I remember correctly, this is considerably slower than using string., so be cautious.

EDIT: Quick test (not sure if this is actually how you do a benchmark lol)
image

Code:

local start = os.clock()

for i = 1, 1000000 do
	local str = ("hello"):match("ello")
end

print(`string:match ended in {os.clock() - start}`)

local start = os.clock()

for i = 1, 1000000 do
	local str = string.match("hello", "ello")
end

print(`string.match ended in {os.clock() - start}`)
2 Likes

Hm, never thought about that. Way I have suggested above is really slover by 10-20%.
I think I’ll rewrite this post so people WON’T make like that now…

1 Like

I was using the str:match(...) pattern instead of string.match(str, ...) for over 10 years. Just this year, I switched back to using string.match(str, ...) (et. al.) due to the performance overhead. In reality, it’s more-so that Luau optimizes for global library functions and caches them, e.g. multiple accesses of string.match don’t have to do a hash lookup in the string library every time; just once.

2 Likes

Hmm…

Test Code

local a = os.clock()

local count = 1000000
for i = 1, count do
	local str = "Hello world!"
	string.match(str, "%s+")
end

local b = os.clock()

for i = 1, count do
	local str = "Hello world!"
	str:match("%s+")
end

local c = os.clock()

game.LogService:ClearOutput()
warn("string.match:", (b-a)*1000, "ms")
warn("str:match:", (c-b)*1000, "ms")

warn(`str:match is {math.floor((1-(b-a)/(c-b)) * 100)}% slower`)


It’s pretty random, so I would say it’s negligible.

1 Like

Strange, when I tested it I have got constant results that “trick” is slower by 10-20%

Wait…
Is ("hello") this part here ("hello"):match("ello") takes time to “generate”?

1 Like
--!strict
--!optimize 2
--!native

local count = 1e6

local a = os.clock()

local str = "123 Goodbye world!"

for i = 1, count do
	assert(string.match(str, "%d+") == "123")
	assert(string.gsub(str, "Goodbye", "Hello") == "123 Hello world!")
	assert(string.lower(str) == "123 goodbye world!")
end

local b = os.clock()

for i = 1, count do
	assert(str:match("%d+") == "123")
	assert(str:gsub("Goodbye", "Hello") == "123 Hello world!")
	assert(str:lower() == "123 goodbye world!")
end

local c = os.clock()

game:GetService("LogService"):ClearOutput()
warn("string library", (b - a) * 1000, "ms")
warn("string methods", (c - b) * 1000, "ms")

warn(`string methods are {math.floor((1 - (b - a)/(c - b)) * 100)}% slower`)

image

1 Like

What is this?

2 Likes

An imaginary sign that roblox optimizes by

2 Likes

I’ve researched on this in the past and I can definitely say that using the string methods on the actual string like "":upper() is ~(1 - 10)% slower than actually using string.upper("").

The percentage mainly depends on how frequently you’re messing around with strings. For a game that works a lot with strings, I’d recommend using string.method() instead of "":method

1 Like

Now everyone is talking about the speed of the functions.

though I am aware of the mentioned methods since I began programming

2 Likes

Due to global sandboxing and the ability to dynamically deoptimize code running in impure environments, in pure environments we go beyond optimizing the interpreter and optimize many built-in functions through a “fastcall” mechanism.

For this mechanism to work, function call must be “obvious” to the compiler - it needs to call a builtin function directly, e.g. math.max(x, 1), although it also works if the function is “localized” (local max = math.max); this mechanism doesn’t work for indirect function calls unless they were inlined during compilation, and doesn’t work for method calls (so calling string.byte is more efficient than s:byte).

1 Like