But return lists are more than an optimization. Lua is a first-class functional language with guaranteed tail-call optimization. And Lua maintains strong semantic symmetry between its C API and in-language constructs. In both cases return lists provide an extremely elegant way for composing function calls, including composing mixtures of Lua and Lua C functions.
For example, returning a list in C is as simple as `push; push; return 2`, whereas in languages that require an array or tuple you need to need to create a separate object and then insert your value (by index or name). It's worth noting that Lua can handle allocation failure gracefully, throwing an error back to the more recent protected call while maintaining a clean state (e.g., OOM from an event loop client handler won't crash your app and the hundreds of thousands of other connections). Many simple functions that operate on the stack (e.g. lua_pushinteger) are guaranteed not to dynamically allocate. Such guarantees can make writing OOM-safe Lua C API code much easier.
If you look at it from the perspective of the C FFI, return lists make a ton of sense. Indeed, they're integral to the C API semantics, which is defined in terms of an abstract invocation stack--which is in fact implemented as a contiguous array.