[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Depth indexing of nil
- From: Parke <parke.nexus@...>
- Date: Thu, 9 Jul 2015 09:41:44 -0700
>> -- 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