lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Timon Christl wrote:
Use the Source, Luke! When looking into the Lua source code, you can
find these lines in luaV_concat(), which is the function that
implements the concat operator:

   if (!tostring(L, top-2) || !tostring(L, top-1)) {
     if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))


I had already fixed the problem in my local copy of Lua 5.1.1; here is the patch. I was more interested if this was a bug (because the code implemented is different to the manual) or a defect in the manual (the add metamethod describes how concat works).

284c283,284
<     if (!tostring(L, top-2) || !tostring(L, top-1)) {
---
>     if (!(ttisnumber(top-2) || ttisstring(top-2)) ||
> 		!(ttisnumber(top-1) || ttisstring(top-1))) {
287c287,288
<     } else if (tsvalue(top-1)->len > 0) {  /* if len=0, do nothing */
---
>     } else if (tostring(L, top-2), tostring(L, top-1),
>        	tsvalue(top-1)->len > 0) {  /* if len=0, do nothing */

This first tries to convert at least one of the two topmost stack
values into a string, and only if this fails it will try to call the
metamethod of one of the two values. tostring() is a macro that
evaluates to true in one of two cases: when the value really is a
string, or when a call to luaV_tostring() returns true. And this
function is where the problem lies. If it is called with a number
value as argument, it will silently replace the value with a value of
type string that contains the string representation of the number.
This behaviour is indeed documented, but only for the C API function
lua_tostring(), not in the section about metamethods.

I would not really call this a bug. But I think it is a weakness in
the design of how Lua's metamethods work, and definitely a case of
incomplete documentation.

Workaround: You might try to parse the string in your concat
implementation to see if it can be converted back to a number. Yes
this means two unnecessary conversions, but this shouldn't be a speed
problem. Or, you shouldn't be using a scripting language for this if
it is.


Not really useful to me as a workaround, there is no way of determining if a string or a number was being concatenated, or if I have to check to see if a string parameter looks like a number or not.

Another possibility would be to replace the concat operator with a
function. It would not be as pretty, but it would work, since
arguments for functions do not suffer from the same problem. So
instead of x=n..ud you would write something like x=myconcat(n,ud).
And theoretically it should save a few CPU cycles :-)

One of the criticisms raised on this list with wxLua (I am one of the original authors) was that the wxLua interface was insufficiently Lua-like, so in the new interface I have been working on I have been attempting to make it more so. Adding a myconcat function seems like a regression to me.