optimizing away a constant no-op function

66 views
Skip to first unread message

Thijs Schreijer

unread,
Nov 3, 2025, 5:37:54 AM (4 days ago) Nov 3
to lu...@googlegroups.com
I have the following (example) code:



local const noop = function() end

local function main()
noop()
print("done")
end

main()



When I check the generated bytecode I found that it generates slightly different bytecode based on the "const" keyword, as to be expected.

I hoped however it would omit the call to `noop()` all together in case it was a constant no-op function. Since it is a constant, it should be safe to remove the call.


The rationale behind this test:

I'm experimenting with parameter validation. In the Lua sourcecode there are macros that can be enabled that do extensive parameter checks to see if one is using the c api proper. So I'm trying to implementing something similar for Lua code, without an additional parser step, and also without overhead if not needed. Here's the concept:



local const noop = function() end

local function generate_validator(spec)
if not os.getenv("LUA_ASSERT_ARGS") then
-- validation disabled, so "be light"
return noop
else
-- generate a full blown parameter validator function from the specs
return require("validator").generate(spec)
end
end


local main do
local const main_validator = generate_validator {
-- extensive description goes here (something like a JSON schema),
-- becomes a constant no-op if LUA_ASSERT_ARGS is undefined
}

function main(param1, param2, param3)
main_validator(param1, param2, param3) -- if a const no-op, ideally no byte code generated
print("done")
end
end

main(1, 2, 3)



Would be nice to have this optimized.

Thijs

Sainan

unread,
Nov 3, 2025, 5:54:45 AM (4 days ago) Nov 3
to lu...@googlegroups.com
You declared a local called 'const' and a global called 'noop'. Neither of which are, in fact, constants.

You meant to use 'local noop <const>', but even so, Lua does not have an optimising compiler as it would be a needless amount of added complexity.

You might be interested in patching the parser for some more preprocessor-like features, similar to what Pluto does: https://pluto-lang.org/docs/New%20Features/Preprocessing

-- Sainan

Thijs Schreijer

unread,
Nov 3, 2025, 7:08:44 AM (4 days ago) Nov 3
to lu...@googlegroups.com
On Mon, 3 Nov 2025, at 11:54, 'Sainan' via lua-l wrote:
> You declared a local called 'const' and a global called 'noop'. Neither
> of which are, in fact, constants.

dang, something looked a bit fishy already to me (haven't used const at all yet), then assumed as it compiled it was correct. Silly me. Thanks for pointing it out.

> You might be interested in patching the parser for some more
> preprocessor-like features, similar to what Pluto does:
> https://pluto-lang.org/docs/New%20Features/Preprocessing

I explicitly do not want to modify Lua sources, stock Lua intended.


So here is the proper code example:



local noop <const> = function() end

local function main()
noop()
print("done")
end

main()



And the proper full example:



local noop <const> = function() end

local function generate_validator(spec)
if not os.getenv("LUA_ASSERT_ARGS") then
-- validation disabled, so "be light"
return noop
else
-- generate a full blown parameter validator function from the specs
return require("validator").generate(spec)
end
end


local main do
local main_validator <const> = generate_validator {
-- extensive description goes here (something like a JSON schema),
-- becomes a constant no-op if LUA_ASSERT_ARGS is undefined
}

function main(param1, param2, param3)
main_validator(param1, param2, param3) -- if a const no-op, ideally no byte code generated
print("done")
end
end

main(1, 2, 3)



> You meant to use 'local noop <const>', but even so, Lua does not have
> an optimising compiler as it would be a needless amount of added
> complexity.

I recently read somewhere (on this list probably that const has no runtime effects, as it is checked during compilation, not runtime. That triggered me into the above, trying to see if this was also checked at compile time.

Whether it is a "needless amount of added complexity" is an opinion. To me it is just moving cost from runtime to compile time.

This is the use case I had in mind, I would be curious to know if others see other uses for something like this.

Thijs

Scott Morgan

unread,
Nov 3, 2025, 7:39:20 AM (4 days ago) Nov 3
to lu...@googlegroups.com
On 03/11/2025 10:54, 'Sainan' via lua-l wrote:
> but even so, Lua does not have an optimising compiler as it would be a needless amount of added complexity.

I'd wonder if there's a valid reason to keep empty function calls in
place, if you need them to trigger a debug hook.

Scott

Andrey Dobrovolsky

unread,
Nov 3, 2025, 8:35:33 AM (4 days ago) Nov 3
to lu...@googlegroups.com
Hi Thijs,

> Would be nice to have this optimized.

You have excellent chances to perform all the necessary optimizations
fitting Your taste obtaining the function's bytecode with the help of
string.dump(), enhancing the bytecode and reloading the function with
load().

-- Andrew

пн, 3 лист. 2025 р. о 14:39 'Scott Morgan' via lua-l
<lu...@googlegroups.com> пише:
> --
> You received this message because you are subscribed to the Google Groups "lua-l" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/lua-l/a4e7f737-ab21-41b3-bb31-4f80ca45cf28%40blueyonder.co.uk.

Thijs Schreijer

unread,
Nov 3, 2025, 2:02:15 PM (3 days ago) Nov 3
to lu...@googlegroups.com
On Mon, 3 Nov 2025, at 14:35, Andrey Dobrovolsky wrote:
> Hi Thijs,
>
>> Would be nice to have this optimized.
>
> You have excellent chances to perform all the necessary optimizations
> fitting Your taste obtaining the function's bytecode with the help of
> string.dump(), enhancing the bytecode and reloading the function with
> load().
>
> -- Andrew
>

This would be a fun challenge probably. But quickly ends up being a rabbit hole.
The main problem I see is that it would have the traverse all the function's upvalues as well to find local functions that also might use this construct again. Not to mention it would depend on the version specific bytecode of a single Lua version.

Thijs

Andrey Dobrovolsky

unread,
Nov 3, 2025, 2:53:40 PM (3 days ago) Nov 3
to lu...@googlegroups.com
пн, 3 лист. 2025 р. о 21:02 'Thijs Schreijer' via lua-l
<lu...@googlegroups.com> пише:

> This would be a fun challenge probably. But quickly ends up being a rabbit hole.
> The main problem I see is that it would have the traverse all the function's upvalues as well to find local functions that also might use this construct again. Not to mention it would depend on the version specific bytecode of a single Lua version.

Oh, I didn't mean some sophisticated techniques. But in Your example

> main_validator(param1, param2, param3) -- if a const no-op, ideally no byte code generated

it may be just stripping out a handful of bytes. If I am not mistaken.
Maybe some other cases exist when such self editing may be beneficial.
I never (yet) practiced this, Your post led me to the conclusion
(theoretical) that probably it is not impossible.

-- Andrew

Luiz Henrique de Figueiredo

unread,
Nov 3, 2025, 8:19:50 PM (3 days ago) Nov 3
to lu...@googlegroups.com
> Would be nice to have this optimized.

If you can use a preprocessor then it should be simple to use my
ltokenp for doing so. Check the assert.lua example; it removes calls
to assert.
https://web.tecgraf.puc-rio.br/~lhf/ftp/lua/#ltokenp
Reply all
Reply to author
Forward
0 new messages