like robbie says, the comma means that both lines are read together as a parallel /multiple assignment statement (local is a red herring)
[1] a = 'foo', print(a)
same as
[2] a = 'foo', nil
which is the same as
[3] a, _ = 'foo', nil
for details:
https://www.lua.org/manual/5.4/manual.html#3.3.3
https://www.lua.org/manual/5.4/manual.html#3.4.12
Note that a single expression in a place that expects a list of expressions is the last expression in that (singleton) list.
If there are more values than needed, the extra values are thrown away
parallel assignment is a nice feature. (…right? i guess.(*)) i agree, the adjustment rules are a little surprising - one might reasonably expect a syntax error instead. (i was also initially confused by the manual and thought that [2] and [3] above would evaluate differently, which they don’t.)
(*)
who actually uses parallel assignement? i only ever use it to avoid creating a temp variable when swapping things: x, y = y, x.
multireturn functions are kind of neat, though i usually don’t remember it’s a possibility (and maybe i think a table is just clearer)
function mr() return 555, 666 end
x, y = mr()
but i find it irritating to read code where it’s just been used to save line count:
local x, y, z, foo, bar, baz, zap = 1, 2, 'whereami', 'idk', 'wtf'
(please don’t do this, it is so hard to read)
the lua language is both simple in imeplementation (to keep a low profile) and actually relatively complex as far as the range of syntax it supports. i honestly don’t love that combination. i find myself writing more bugs in lua than in other languages, and i resent the keyword noise.
oh well.
i’ve been turning to wren lately as a default scripting language choice. it’s syntax is far more restrictive, but it directly supports (my) commonly used patterns more succinctly, it’s small and simple and fast, etc.