I think you're just overcomplicating it tbh
That's your opinion. It's a fact that "." and ":" are syntaxic sugars of Lua and are not real operators. They cannot interact freely But all can be made with closures (for binding the upvalues) and with the "[]" indexing operator (in tables). And a fact as well that "self" is not a keyword but a conventional name of the first parameter of a function that can be called with ":".
"self" is just the *implicit* parameter name used when we DECLARE a function with the ":" syntaxic sugar. We an do everything in Lua without ever using "." or ":", but only using "[]" and passing all parameters explicitly. for this reason "self" is not even a reserved keyword (it can be renamed as we want if we don't use the ":"-enhanced function declaration).
Once you understand it, there are three ways to pass parameters to functions:
- by parameters on stack, which become "registers" just like other local variables declared with "local" in the function body (the fastest method, but limited to ~250 variables): this includes the "self" parameter.
- by the function's metatable, which includes its environment (this is fast too because it is allocated on the heap only once by thread and preserved across multiple calls in the same thread/coroutine: there's no limit on the number of parameters): this includes the access to the "global" environment (actually not global, it's not static like in C but scoped recursively and specific to each thread; it's sort of "TLS" except that multiple threads can communicate objects as all these objects are allocated on the same global heap using the same Allocator, if all threads are created in Lua from the same main thread instanciated in C by the Lua engine)
- by external variables bound into upvalues with the closure (it is the slowest method because the closure is allocated on each call and needs to be garbage collected and it stresses a lot the garbage collector: this woks for returning multiple values from the function)
The closures are interesting and facilitates a lot programming in Lua, but it has a significant runtime cost and stresses the GC at each call.
If there's something to do to the Lua engine is to rework the way upvalues are allocated: they should be on the call stack as much as possible (e.g. for up to ~250 upvalues) and not on the heap. This would dramatically increase the performance of closures and reduce a lot the stress on the GC, they would become as fast as function parameters and local variables, working like "registers" (with negative index), and would simplify also the instruction set for the bytecode and the complexity of the compiler, which would also not need to create static "prototypes" for each closure and make any run-time binding (but this would require to increase a bit the size of stacks per thread (stacks are allocated only once on the heap before the thread starts): this increase would have no cost because we save lot of uses on the heap and would save lot of work that needs to be made by the GC... The global memory footprint would be much lower wioth higher performance too.