I do see the potential issue with the way the methods are called. With my suggested behavior, it only comes up if you have mixed assignments to t[i] and t[i,j] on the same table and the __newindex isn't built to deal with it. I sort of feel like that's a case of "well, then don't do that" -- if you're intending your table to support multi-indexed data, then you shouldn't ever assign data to a publicly-accessible first index, and the failure mode would simply be considered a bug in the code.
I don't feel strongly about this. But the asymmetry in the behavior is unfortunate. We end up back in the default behavior. It would be nice if the native table implementation knew about multiple indices. Maybe someone can come up with an implementation that is just as good as the current one is for single indices but that also works very well for multiple indices. Then the __index and __newindex would only be invoked for missing multi-index combinations.
But then the default behavior would be triggered by something like t[f()], bringing the incompatibility back. If the number of indices was defined syntactically, rather than at run time, there would be no incompatibility.
Maybe a dimension field on the metatable that defaults to 1? Or a mode character that enables multi-indexing? Then the native table can know about it and you just have to opt in. Maybe put a convenience function in the table library to enable "t = table.dim(2)" for ease of reading.
Or it could be the other way around, making the default dimension "mixed" and letting you specify a fixed number for tables that need to care, but I feel like that's a little bit more surprising of behavior since multi-indexing is.
Of course there's always the standard "wrap it in parens" way to force it down to one value.
Now if somebody finds a way for __lvaluecall to receive multiple *values* along with multiple indices, we could even have tables that store and return multi-dimensional data.
Not sure how to work this out, but it sure would be cool.
At that point you might as well just promote tuples to a first-class object instead of juggling them implicitly with the varargs syntax. That would solve ALL of the problems.
Except for Roberto's. :)
Good point. ;)