Hehe, I have a WIP blog post about this :-)
I used to think that the "select loop" is the preferred way to iterate varargs too. It has the desired semantics: It iterates nils, and it's simple enough.
Unfortunately, it's only fast (linear time) on LuaJIT.
On PUC Lua, it's quadratic time in the length of the vararg, because a whole lot of copying happens on the stack.
That is, the "proper" way to iterate a vararg in PUC Lua is to pack it up in a table t with table.pack, and then iterate that up to t.n using numeric for.
(On 5.1, you need to polyfill table.pack using select("#", ...) but that's okay.)
Lua 5.5 finally adds a proper, more efficient way with vararg tables, see
https://lua.org/manual/5.5/manual.html#3.4.10 for details.
Effectively your example becomes:
function f(...t)
for i = 1, t.n do