lua-users home
lua-l archive

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


On 12/24/06, Paul.Winwood <paul.winwood@gmail.com> wrote:
I have implemented a Lua (5.1.1) userdata that implements the __concat
metamethod. A simplified form of my testcase is as follows:

        result = userdata..number
--      result = number..dispatch
         result = dispatch..userdata
         result = userdata..table
         result = table..userdata
         result = userdata..boolean
         result = boolean..userdata
         result = userdata..string
         result = string..userdata
         result = userdata..func
         result = func..userdata
         result = userdata..thread
         result = thread..userdata

where userdata is a variable containing my userdata object (and number,
table, boolean, func and thread are variables containing the
corresponding Lua type). Everything works as expected but for the
commented out case

        result = number..userdata

In this case the number is automatically 'promoted' to a string type
before my metamethod is called. Is this behaviour correct because this
is not as described by my reading of section 2.8 of the manual?

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))

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.

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 :-)

I hope this helps. I'm not really a Lua expert, but I enjoy reading
well-written source code from time to time, and since it is Christmas
I just felt like looking around in Lua's source code for some time.

--
(defun f(p x)(If(Eq x nil)nil(If(p(Car x))(Cons(Car x)(f p(Cdr x)))(f p
(Cdr x)))))(defun q(x)(Q nil x))(defun Q(a x)(If(Eq x nil)a(Q(Cons(Car
x)(Q a(f(Lt(Car x))(Cdr x))))(f(Gt(Car x))(Cdr x)))))