[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: [ANN] Lua 5.4.0 (alpha) now available
- From: Sergey Kovalev <kovserg33@...>
- Date: Thu, 18 Jul 2019 09:45:10 +0300
чт, 18 июл. 2019 г. в 02:15, Hisham <h@hisham.hm>:
>
>
> I know, that was my point: to explain to Dirk why this feature is
> making into Lua 5.4 iterators, and why it is something necessary and
> not bloat.
>
> Yes, I know. In fact, it could be generalized: the <toclose> modifier
> can be expressed purely in terms of the "closing value" support of the
> generic-for in Lua 5.4. Consider this function, scoped():
>
> ----------------------------------------
> function scoped(...)
> local cv = ...
> local args = table.pack(...)
> return function(_, v)
> if v == cv then
> cv = nil
>
> -- hack: force false instead of nil so that
> -- for runs in case of an error
> if args.n > 1 and args[1] == nil then
> args[1] = false
> end
>
> return table.unpack(args, 1, args.n)
> end
> end, nil, cv, cv
> end
> ----------------------------------------
>
> ----------------------------------------
> -- example use:
> ----------------------------------------
> local fref
>
> for f, err in scoped(io.open("scoped.lua")) do
> if err then
> print(err)
> break
> end
> fref = f
> print(f:read("*a"))
> end
>
> print(io.type(fref)) -- prints "closed file", hooray!
> ----------------------------------------
>
> The above implementation, while it does demonstrate that <toclose> can
> be expressed in terms of generic-for, is too heavyweight for
> real-world use (with the extra closure and table packing and
> unpacking). That's why I suggested adding it as a core language
> feature instead of <toclose>.
>
> Let's say I want to make the equivalent of the above program (have a
> resource whose lifetime is scoped to a block) and use <toclose>. This
> is honest-to-goodness the nicest way I managed to produce a version of
> the above program using <toclose>, I'm not sure I like it better than
> the one above:
>
> ----------------------------------------
> local fref
>
> do
> local f, err = io.open("scoped.lua")
> local <toclose> f = f -- *****
> if err then
> print(err)
> else
> fref = f
> print(f:read("*a"))
> end
> end
>
> print(io.type(fref)) -- prints "closed file", hooray!
> ----------------------------------------
>
> ^ ***** to reiterate a previous post, it's really bad we need a
> separate line for this. I might as well just write f:close() at the
> end of the block. (It also throws off linters, which complain at the
> shadowing.) If nothing else changes about to-be-closed variables
> before Lua 5.4 final, I'd like at least this to be addressed.
>
> I agree with you that one downside of this proposal is that it
> requires a nesting level for each closable variable within scope (but
> remember you can't make an array of closable variables, even with
> <toclose>; you can make a closable array, though, as Gé suggested). On
> the other hand, providing a visual cue about the lifetime of resources
> is also an advantage.
>
> -- Hisham
>
Idea is good but syntax is inconsistent. It is too far from that it
should. <toclose> in for look nice but <toclose> in local is not.
Do you consider following scope prototype:
function io.scope()
local m=setmetatable({ files={} },{index=io})
function m.open(name,mode)
local f,err=io.open(name,mode)
if f then table.insert(m.files,f) end
return f,err
end
function m.popen(name,mode)
local f,err=io.popen(name,mode)
if f then table.insert(m.files,f) end
return f,err
end
local close_all=function()
for i=#m.files,1,-1 do
local f=m.files[i]
m.files[i]=nil
if io.type(f)=='file' then io.close(f) end
end
end
m.close_all=close_all
return function(ctx,prev)
if prev==nil then
return m
else
m.close_all() -- lua 5.3: will not work with break inside for
end
end,nil,nil,setmetatable({},{__close=close_all}) -- lua 5.4
end
-- usage:
for io in io.scope() do
local s,serr=io.open("src","rb")
local d,derr=io.open("dst","wb")
if s and d then d:write(s:read()) end
end