diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-08-24 10:17:54 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-08-24 10:17:54 -0300 |
commit | 8c8a91f2ef7acccb99e3737913faad8d48b39571 (patch) | |
tree | 0807151944b7f7fd00eedfcfe94b4ee26fe25b21 | |
parent | f99509581ee73c1c2dbddb3398e87c098771d31f (diff) | |
download | lua-8c8a91f2ef7acccb99e3737913faad8d48b39571.tar.gz lua-8c8a91f2ef7acccb99e3737913faad8d48b39571.tar.bz2 lua-8c8a91f2ef7acccb99e3737913faad8d48b39571.zip |
Deprecated the emulation of '__le' using '__lt'
As hinted in the manual for Lua 5.3, the emulation of the metamethod
for '__le' using '__le' has been deprecated. It is slow, complicates
the logic, and it is easy to avoid this emulation by defining a proper
'__le' function.
Moreover, often this emulation was used wrongly, with a programmer
assuming that an order is total when it is not (e.g., NaN in
floating-point numbers).
-rw-r--r-- | lstate.h | 8 | ||||
-rw-r--r-- | ltests.h | 1 | ||||
-rw-r--r-- | ltm.c | 2 | ||||
-rw-r--r-- | luaconf.h | 8 | ||||
-rw-r--r-- | lvm.c | 2 | ||||
-rw-r--r-- | manual/manual.of | 21 | ||||
-rw-r--r-- | testes/coroutine.lua | 8 | ||||
-rw-r--r-- | testes/events.lua | 34 |
8 files changed, 44 insertions, 40 deletions
@@ -138,9 +138,11 @@ typedef struct CallInfo { | |||
138 | #define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ | 138 | #define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ |
139 | #define CIST_TAIL (1<<4) /* call was tail called */ | 139 | #define CIST_TAIL (1<<4) /* call was tail called */ |
140 | #define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ | 140 | #define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ |
141 | #define CIST_LEQ (1<<6) /* using __lt for __le */ | 141 | #define CIST_FIN (1<<6) /* call is running a finalizer */ |
142 | #define CIST_FIN (1<<7) /* call is running a finalizer */ | 142 | #define CIST_TRAN (1<<7) /* 'ci' has transfer information */ |
143 | #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ | 143 | #if defined(LUA_COMPAT_LT_LE) |
144 | #define CIST_LEQ (1<<8) /* using __lt for __le */ | ||
145 | #endif | ||
144 | 146 | ||
145 | /* active function is a Lua function */ | 147 | /* active function is a Lua function */ |
146 | #define isLua(ci) (!((ci)->callstatus & CIST_C)) | 148 | #define isLua(ci) (!((ci)->callstatus & CIST_C)) |
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | /* test Lua with compatibility code */ | 14 | /* test Lua with compatibility code */ |
15 | #define LUA_COMPAT_MATHLIB | 15 | #define LUA_COMPAT_MATHLIB |
16 | #define LUA_COMPAT_LT_LE | ||
16 | 17 | ||
17 | 18 | ||
18 | #define LUA_DEBUG | 19 | #define LUA_DEBUG |
@@ -188,6 +188,7 @@ int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
188 | TMS event) { | 188 | TMS event) { |
189 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ | 189 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ |
190 | return !l_isfalse(s2v(L->top)); | 190 | return !l_isfalse(s2v(L->top)); |
191 | #if defined(LUA_COMPAT_LT_LE) | ||
191 | else if (event == TM_LE) { | 192 | else if (event == TM_LE) { |
192 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ | 193 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ |
193 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ | 194 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ |
@@ -197,6 +198,7 @@ int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
197 | } | 198 | } |
198 | /* else error will remove this 'ci'; no need to clear mark */ | 199 | /* else error will remove this 'ci'; no need to clear mark */ |
199 | } | 200 | } |
201 | #endif | ||
200 | luaG_ordererror(L, p1, p2); /* no metamethod found */ | 202 | luaG_ordererror(L, p1, p2); /* no metamethod found */ |
201 | return 0; /* to avoid warnings */ | 203 | return 0; /* to avoid warnings */ |
202 | } | 204 | } |
@@ -295,7 +295,7 @@ | |||
295 | */ | 295 | */ |
296 | 296 | ||
297 | /* | 297 | /* |
298 | @@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.2. | 298 | @@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. |
299 | ** You can define it to get all options, or change specific options | 299 | ** You can define it to get all options, or change specific options |
300 | ** to fit your specific needs. | 300 | ** to fit your specific needs. |
301 | */ | 301 | */ |
@@ -316,6 +316,12 @@ | |||
316 | */ | 316 | */ |
317 | #define LUA_COMPAT_APIINTCASTS | 317 | #define LUA_COMPAT_APIINTCASTS |
318 | 318 | ||
319 | /* | ||
320 | @@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod | ||
321 | ** using '__lt'. | ||
322 | */ | ||
323 | #define LUA_COMPAT_LT_LE | ||
324 | |||
319 | #endif /* } */ | 325 | #endif /* } */ |
320 | 326 | ||
321 | 327 | ||
@@ -754,10 +754,12 @@ void luaV_finishOp (lua_State *L) { | |||
754 | case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ | 754 | case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ |
755 | int res = !l_isfalse(s2v(L->top - 1)); | 755 | int res = !l_isfalse(s2v(L->top - 1)); |
756 | L->top--; | 756 | L->top--; |
757 | #if defined(LUA_COMPAT_LT_LE) | ||
757 | if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ | 758 | if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ |
758 | ci->callstatus ^= CIST_LEQ; /* clear mark */ | 759 | ci->callstatus ^= CIST_LEQ; /* clear mark */ |
759 | res = !res; /* negate result */ | 760 | res = !res; /* negate result */ |
760 | } | 761 | } |
762 | #endif | ||
761 | lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); | 763 | lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); |
762 | if (res != GETARG_k(inst)) /* condition failed? */ | 764 | if (res != GETARG_k(inst)) /* condition failed? */ |
763 | ci->u.l.savedpc++; /* skip jump instruction */ | 765 | ci->u.l.savedpc++; /* skip jump instruction */ |
diff --git a/manual/manual.of b/manual/manual.of index 5a8b1b2c..47a551bf 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -474,17 +474,7 @@ The result of the call is always converted to a boolean. | |||
474 | 474 | ||
475 | @item{@idx{__le}| | 475 | @item{@idx{__le}| |
476 | the less equal (@T{<=}) operation. | 476 | the less equal (@T{<=}) operation. |
477 | Unlike other operations, | 477 | Behavior similar to the less than operation. |
478 | the less-equal operation can use two different events. | ||
479 | First, Lua looks for the @idx{__le} metamethod in both operands, | ||
480 | like in the less than operation. | ||
481 | If it cannot find such a metamethod, | ||
482 | then it will try the @idx{__lt} metamethod, | ||
483 | assuming that @T{a <= b} is equivalent to @T{not (b < a)}. | ||
484 | As with the other comparison operators, | ||
485 | the result is always a boolean. | ||
486 | (This use of the @idx{__lt} event can be removed in future versions; | ||
487 | it is also slower than a real @idx{__le} metamethod.) | ||
488 | } | 478 | } |
489 | 479 | ||
490 | @item{@idx{__index}| | 480 | @item{@idx{__index}| |
@@ -1643,7 +1633,8 @@ all operations @emphx{wrap around}, | |||
1643 | according to the usual rules of two-complement arithmetic. | 1633 | according to the usual rules of two-complement arithmetic. |
1644 | (In other words, | 1634 | (In other words, |
1645 | they return the unique representable integer | 1635 | they return the unique representable integer |
1646 | that is equal modulo @M{2@sp{64}} to the mathematical result.) | 1636 | that is equal modulo @M{2@sp{n}} to the mathematical result, |
1637 | where @M{n} is the number of bits of the integer type.) | ||
1647 | } | 1638 | } |
1648 | 1639 | ||
1649 | @sect3{bitwise| @title{Bitwise Operators} | 1640 | @sect3{bitwise| @title{Bitwise Operators} |
@@ -8537,6 +8528,12 @@ For instance, the result of @T{"1" + "2"} now is an integer, | |||
8537 | not a float. | 8528 | not a float. |
8538 | } | 8529 | } |
8539 | 8530 | ||
8531 | @item{ | ||
8532 | The use of the @idx{__lt} metamethod to emulate @id{__le} | ||
8533 | has been removed. | ||
8534 | When needed, this metamethod must be explicitly defined. | ||
8535 | } | ||
8536 | |||
8540 | } | 8537 | } |
8541 | 8538 | ||
8542 | } | 8539 | } |
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 182c1e18..36eae44a 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
@@ -1,4 +1,4 @@ | |||
1 | -- $Id: testes/coroutine.lua $ | 1 | -- $Id: testes/coroutine.lua 2018-07-25 15:31:04 -0300 $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file all.lua |
3 | 3 | ||
4 | print "testing coroutines" | 4 | print "testing coroutines" |
@@ -619,10 +619,8 @@ end | |||
619 | 619 | ||
620 | assert(run(function () if (a>=b) then return '>=' else return '<' end end, | 620 | assert(run(function () if (a>=b) then return '>=' else return '<' end end, |
621 | {"le", "sub"}) == "<") | 621 | {"le", "sub"}) == "<") |
622 | -- '<=' using '<' | ||
623 | mt.__le = nil | ||
624 | assert(run(function () if (a<=b) then return '<=' else return '>' end end, | 622 | assert(run(function () if (a<=b) then return '<=' else return '>' end end, |
625 | {"lt"}) == "<=") | 623 | {"le", "sub"}) == "<=") |
626 | assert(run(function () if (a==b) then return '==' else return '~=' end end, | 624 | assert(run(function () if (a==b) then return '==' else return '~=' end end, |
627 | {"eq"}) == "~=") | 625 | {"eq"}) == "~=") |
628 | 626 | ||
@@ -677,7 +675,7 @@ do -- a few more tests for comparsion operators | |||
677 | return val(a) < val(b) | 675 | return val(a) < val(b) |
678 | end, | 676 | end, |
679 | } | 677 | } |
680 | local mt2 = { __lt = mt1.__lt } -- no __le | 678 | local mt2 = { __lt = mt1.__lt, __le = mt1.__le } |
681 | 679 | ||
682 | local function run (f) | 680 | local function run (f) |
683 | local co = coroutine.wrap(f) | 681 | local co = coroutine.wrap(f) |
diff --git a/testes/events.lua b/testes/events.lua index 21a822a7..c4d43d51 100644 --- a/testes/events.lua +++ b/testes/events.lua | |||
@@ -1,4 +1,4 @@ | |||
1 | -- $Id: testes/events.lua $ | 1 | -- $Id: testes/events.lua 2018-07-25 15:31:04 -0300 $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file all.lua |
3 | 3 | ||
4 | print('testing metatables') | 4 | print('testing metatables') |
@@ -217,6 +217,13 @@ t.__lt = function (a,b,c) | |||
217 | return a<b, "dummy" | 217 | return a<b, "dummy" |
218 | end | 218 | end |
219 | 219 | ||
220 | t.__le = function (a,b,c) | ||
221 | assert(c == nil) | ||
222 | if type(a) == 'table' then a = a.x end | ||
223 | if type(b) == 'table' then b = b.x end | ||
224 | return a<=b, "dummy" | ||
225 | end | ||
226 | |||
220 | function Op(x) return setmetatable({x=x}, t) end | 227 | function Op(x) return setmetatable({x=x}, t) end |
221 | 228 | ||
222 | local function test () | 229 | local function test () |
@@ -236,15 +243,6 @@ end | |||
236 | 243 | ||
237 | test() | 244 | test() |
238 | 245 | ||
239 | t.__le = function (a,b,c) | ||
240 | assert(c == nil) | ||
241 | if type(a) == 'table' then a = a.x end | ||
242 | if type(b) == 'table' then b = b.x end | ||
243 | return a<=b, "dummy" | ||
244 | end | ||
245 | |||
246 | test() -- retest comparisons, now using both `lt' and `le' | ||
247 | |||
248 | 246 | ||
249 | -- test `partial order' | 247 | -- test `partial order' |
250 | 248 | ||
@@ -266,14 +264,6 @@ t.__lt = function (a,b) | |||
266 | return next(b) ~= nil | 264 | return next(b) ~= nil |
267 | end | 265 | end |
268 | 266 | ||
269 | t.__le = nil | ||
270 | |||
271 | assert(Set{1,2,3} < Set{1,2,3,4}) | ||
272 | assert(not(Set{1,2,3,4} < Set{1,2,3,4})) | ||
273 | assert((Set{1,2,3,4} <= Set{1,2,3,4})) | ||
274 | assert((Set{1,2,3,4} >= Set{1,2,3,4})) | ||
275 | assert((Set{1,3} <= Set{3,5})) -- wrong!! model needs a `le' method ;-) | ||
276 | |||
277 | t.__le = function (a,b) | 267 | t.__le = function (a,b) |
278 | for k in pairs(a) do | 268 | for k in pairs(a) do |
279 | if not b[k] then return false end | 269 | if not b[k] then return false end |
@@ -281,10 +271,15 @@ t.__le = function (a,b) | |||
281 | return true | 271 | return true |
282 | end | 272 | end |
283 | 273 | ||
284 | assert(not (Set{1,3} <= Set{3,5})) -- now its OK! | 274 | assert(Set{1,2,3} < Set{1,2,3,4}) |
275 | assert(not(Set{1,2,3,4} < Set{1,2,3,4})) | ||
276 | assert((Set{1,2,3,4} <= Set{1,2,3,4})) | ||
277 | assert((Set{1,2,3,4} >= Set{1,2,3,4})) | ||
278 | assert(not (Set{1,3} <= Set{3,5})) | ||
285 | assert(not(Set{1,3} <= Set{3,5})) | 279 | assert(not(Set{1,3} <= Set{3,5})) |
286 | assert(not(Set{1,3} >= Set{3,5})) | 280 | assert(not(Set{1,3} >= Set{3,5})) |
287 | 281 | ||
282 | |||
288 | t.__eq = function (a,b) | 283 | t.__eq = function (a,b) |
289 | for k in pairs(a) do | 284 | for k in pairs(a) do |
290 | if not b[k] then return false end | 285 | if not b[k] then return false end |
@@ -376,6 +371,7 @@ t1 = {}; c = {}; setmetatable(c, t1) | |||
376 | d = {} | 371 | d = {} |
377 | t1.__eq = function () return true end | 372 | t1.__eq = function () return true end |
378 | t1.__lt = function () return true end | 373 | t1.__lt = function () return true end |
374 | t1.__le = function () return false end | ||
379 | setmetatable(d, t1) | 375 | setmetatable(d, t1) |
380 | assert(c == d and c < d and not(d <= c)) | 376 | assert(c == d and c < d and not(d <= c)) |
381 | t2 = {} | 377 | t2 = {} |