Short external string not recognized by OP_GETVARG

48 views
Skip to first unread message

Xmilia Hermit

unread,
Nov 8, 2025, 8:23:40 AM (4 days ago) Nov 8
to lu...@googlegroups.com
The function luaT_getvararg implementing the main logic of the new
OP_GETVARG bytecode does not work with the short external string 'n'
since it uses `ttisshrstring`. This will result in a return of nil
instead of the number of varargs as can be seen in the following script.

local function test(k, ...|v)
return v[k]
end

do
local f<close> = io.open("n.txt", "wb")
f:write("n")
end
local n
do
local f<close> = io.open("n.txt", "rb")
n = f:read(10000) -- Create short external string n='n'.
end

print(test(n,2))


The output should be `1` but is `nil`. Tested with the current GitHub
mirror head fca974486d12aa29bb6d731fdb5b25055157ece8.

I was also wondering why the `... | varname` was chosen as syntax over
the previous `... = varname` or the in other languages seen `... varname`.

Regards,
Xmilia

Roberto Ierusalimschy

unread,
Nov 8, 2025, 9:35:16 AM (4 days ago) Nov 8
to lu...@googlegroups.com
> The function luaT_getvararg implementing the main logic of the new
> OP_GETVARG bytecode does not work with the short external string 'n' since
> it uses `ttisshrstring`. This will result in a return of nil instead of the
> number of varargs as can be seen in the following script.

Thanks for the feedback.


> I was also wondering why the `... | varname` was chosen as syntax over the
> previous `... = varname` or the in other languages seen `... varname`.

We changed it to '...varname', but it is not in github yet.

-- Roberto

Xmilia Hermit

unread,
Nov 8, 2025, 9:41:52 AM (4 days ago) Nov 8
to lu...@googlegroups.com
The same problem of ignoring short external strings is present in the
__mode of weak tables too.

do
local f<close> = io.open("kv.txt", "wb")
f:write("kv")
end
local kv
do
local f<close> = io.open("kv.txt", "rb")
kv = f:read(10000) -- Create short external string kv='kv'.
end

local w = setmetatable({}, {__mode=kv})
w[{}] = {}

collectgarbage"collect"

assert(next(w)==nil)


Regards,
Xmilia

bil til

unread,
Nov 9, 2025, 7:30:39 AM (3 days ago) Nov 9
to lu...@googlegroups.com
Sorry for this question, if it is too stupid:

Could you give a simple explanation, what the "|v" should do in your
function definition "function( k, ...|v)"?

(possibly with some examples as in reference manual 3.4.11 "Function
Definitions" at the end ... unfortunately there somehow such an
example is missing ... .

Xmilia Hermit

unread,
Nov 9, 2025, 7:47:49 AM (3 days ago) Nov 9
to lu...@googlegroups.com
This is only available in the development/preview version and is not yet
in a release of Lua.
A function such as `function example(...args) <body> end` is shorthand
for `function example(...) local args <const> = table.pack(...) <body> end`.
In case this `args` table is only used in the read versions of
`args[expr]` and `args.name` the table is actually never allocated.
This allows to iterate through the arguments without a table allocation
or requiring to copy all varargs elements when using the `select` method.

For example a sum method which needs to copy all varargs in the uses of
`...` in
function sum(...)
local res = 0
for i=1,select('#', ...) do
res = res + select(i, ...)
end
return res
end

could now be written as
function sum(...args)
local res = 0
for i=1,args.n do
res = res + args[i]
end
return res
end

without a table allocation or all the copies of the varargs done
previously for the `select(i, ...)`.

Regards,
Xmilia

bil til

unread,
Nov 9, 2025, 8:31:21 AM (3 days ago) Nov 9
to lu...@googlegroups.com
Thanks for fast and complete answer, very interesting.

Just looking at your code, this still looks a bit odd to me:

local function test(k, ...|v)
return v[k]
end

... Create short external string n='n'....

print(test(n,2))

If I interprete this correctly, test(n,2) in the last line would then
be the same to invoke print( {2}['n']).

Is it not clear that this should be nil?

Xmilia Hermit

unread,
Nov 9, 2025, 8:34:55 AM (3 days ago) Nov 9
to lu...@googlegroups.com

> If I interprete this correctly, test(n,2) in the last line would then
> be the same to invoke print( {2}['n']).
It should be `print(table.pack(2)['n'])` which would be
`print(({2,n=1})['n'])` since table.pack also writes the number of
elements to the `n` field.
Reply all
Reply to author
Forward
0 new messages