lua-users home
lua-l archive

Re: Depth indexing of nil

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


>> -- somewhere, e.g. module
>> local nothing = setmetatable({}, {
>> __index = function(nothing)
>> return nothing
>> end,
>> __call = function()
>> return nil
>> end,
>> })
>>
>> function maybe(tab)
>> return setmetatable({}, {
>> __index = function(_, key)
>> if tab[key] then
>> return maybe(tab[key])
>> else
>> return nothing
>> end
>> end,
>> __call = function()
>> return tab
>> end,
>> })
>> end
>>
>> -- then
>>
>> a = { b = { c = 123 } }
>>
>> print( maybe(a).b.c() ) -- 123
>> print( maybe(a).x.c() ) -- nil
>>
>> --
>>
>> I'm not 100% happy with it, but I think it'd cover most my use cases.
On Thu, Jul 9, 2015 at 9:16 AM, Roberto Ierusalimschy
<roberto@inf.puc-rio.br> wrote:
>
> When all fields are present, that code will create two new tables plus
> two new closures at each dot: for instance, maybe(a).b.c() creates four
> new objects. That sounds quite expensive.
But it does not have to be that expensive.
do
 local protect = false
 local nothing_mt = {}
 local nothing = setmetatable ( {}, nothing_mt )
 local follow
 function nothing_mt.__index ( t, k )
 if follow then follow = follow [ k ] end
 return nothing end
 function nothing_mt.__call ()
 local t = follow
 follow = nil
 protect = false
 return t end
 function maybe ( t )
 assert ( not protect )
 protect = true
 follow = t
 return nothing end
end
a = { b = { c = 123 } }
print ( maybe (a).b.c() )
print ( maybe (a).x.c() )
In the above, the assert will fail if maybe is called again before
__call. But that could probably be fixed as well, such that only one
new closure would be needed for each nested maybe call. And those
closures could be cached and reused.
-Parke

AltStyle によって変換されたページ (->オリジナル) /