[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: __tonumber metamethod (was Re: Exposure of nil to end-users)
- From: Doug Rogers <doug.rogers@...>
- Date: Thu, 05 Feb 2009 10:13:55 -0500
Michal Kolodziejczyk wrote:
I am also missing __tonumber metamethod...
It seems like this could be a useful feature, but if it were to behave
like __tostring it would be of limited value - limited to programmers
calling tonumber() explicitly.
Note that although the __tostring metamethod exists, it is *not* used by
the VM when it decides that it needs a string value. It is used only by
the Lua base library function tostring(). And the only time tostring()
is called (other than when the developer puts tostring() in his Lua
code) is in the base library implementation of print().
The VM supports coercion to number and string to a limited extent, but
only between those two types because it is simple and relatively fast to
do so.
If you were to do a similar thing for tonumber(), it would never get
used by the Lua internals. Attached is a two-line patch to lbaselib.c
that makes tonumber() behave just like tostring(), honoring a __tonumber
metamethod (without the optional numeric base). This allows the following:
t={}
print(t, tonumber(t)) -- table: 0x807e060 nil
mt={}
mt.__tostring = table.concat
mt.__tonumber = function (self) return self[1] or 0 end
setmetatable(t, mt)
print(t, tonumber(t)) -- 0
t[1]="6"
t[2]=" is perfect"
print(t, tonumber(t)) -- 6 is perfect 6
print(tonumber(t) + 8) -- 14
But this is of limited value since, unlike tostring(), there is no place
that Lua uses tonumber() itself. Still, it might be of value when the
programmer uses tonumber() explicitly.
For example, I think you're looking for this sort of use case (error
messages truncated):
for k = t, 10 do print(k) end
-- stdin:1: 'for' initial value must be a number
print(t + 8)
-- stdin:1: attempt to perform arithmetic on global 't'
Adding support for that kind of thing would have to be done in a way
that resolves the ambiguities that will arise between them and the
operator metamethods (perhaps by a precedence rule, reducing further the
simplicity that is Lua).
For example, the easiest way to provide such support would be to modify
luaV_tonumber() so that it calls the __tonumber metamethod if it exists
(relying on the string table's __tonumber metamethod to achieve its
current behavior). This would allow each of the erroneous examples above
to work (untested).
Developers would then have to decide whether their objects should define
__tonumber or the operator metamethods, since the former would cause the
latter to be performed as normal lua_Number operations. I can think of
examples where a developer would choose the former (defining
__tonumber), say for a bank account object whose balance would be
returned. But for most use cases I would imagine a developer choosing to
redefine the binary operators instead.
Other ways are more complicated. If you have an idea, give it a spin.
Personally, I don't think it is worth the complexity. __tostring is
useful for print() and possibly for serialization of objects, but I
don't see the same usefulness for __tonumber.
Doug
______________________________________________________________________________________
The information contained in this email transmission may contain proprietary and business
sensitive information. If you are not the intended recipient, you are hereby notified that
any review, dissemination, distribution or duplication of this communication is strictly
prohibited. Unauthorized interception of this e-mail is a violation of law. If you are not
the intended recipient, please contact the sender by reply email and immediately destroy all
copies of the original message.
Any technical data and/or information provided with or in this email may be subject to U.S.
export controls law. Export, diversion or disclosure contrary to U.S. law is prohibited.
Such technical data or information is not to be exported from the U.S. or given to any foreign
person in the U.S. without prior written authorization of Elbit Systems of America and the
appropriate U.S. Government agency.
diff -c -r lua-5.1.4-orig/src/lbaselib.c lua-5.1.4/src/lbaselib.c
*** lua-5.1.4-orig/src/lbaselib.c 2008-02-14 11:46:22.000000000 -0500
--- lua-5.1.4/src/lbaselib.c 2009-02-05 08:32:52.000000000 -0500
***************
*** 52,57 ****
--- 52,59 ----
static int luaB_tonumber (lua_State *L) {
int base = luaL_optint(L, 2, 10);
+ if (luaL_callmeta(L, 1, "__tonumber")) /* is there a metafield? */
+ return 1; /* use its value */
if (base == 10) { /* standard conversion */
luaL_checkany(L, 1);
if (lua_isnumber(L, 1)) {