[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: [ANN] Lua 5.4.0 (alpha) now available
- From: Hisham <h@...>
- Date: Wed, 17 Jul 2019 20:14:45 -0300
On Mon, 15 Jul 2019 at 18:07, Sergey Kovalev <kovserg33@gmail.com> wrote:
>
> пн, 15 июл. 2019 г. в 23:01, Hisham <h@hisham.hm>:
> >
> > Have you ever a directory iterator? (e.g. for file in lfs.dir() ) If
> > so, you ran into this problem (maybe without realizing it).
> lua 5.4 solve this using toclose and 4-th parameter for "for"
> print(io.lines"readme.txt")
> function: 0x23af370 nil nil file (0x23af130)
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.
> > So here's an idea for a third one, let's call it "resource for":
> >
> > stat ::=
> > ...
> > for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end |
> > for namelist in explist do block end |
> > for namelist ‘=’ exp do block end |
> > ...
> >
> > (as you can see, it is syntactically a mix of the other two: you can
> > get multiple names on the LHS but a single expression on the RHS: if
> > it uses `=` but no `,`, it's a resource-for). It works in pseudo-code
> > like this:
> >
> > do
> > local x, y, ... = exp
> > if x == nil and y == nil then break end -- only auto-breaks if
> > _all_ values are nil, so we can use libraries which use nil-err
> > errors.
> > block
> > if x then
> > local xmt = getmetatable(x)
> > if xmt and xmt.__close then
> > xmt.__close(x)
> > end
> > end
> > end
> >
> > Example usage:
> >
> > for fd, err = io.open("file", "r") do
> > if err then
> > print("failed!", err)
> > break
> > end
> > print(fd:read("*a"))
> > end
>
> I think solution should cover typical usage scenarios. For example
> open source and destination files for processing and rise error if it
> impossible. "Happy ways" is shorter and simpler to write. Also it
> should be able to handle errors by user if he want it.
> src=auto(io.close){ io.open(src_filename,"rb") }
> dst=auto(io.close){ io.open(dst_filename,"wb") }
> -- do somethig with src and dst
>
>
> > You could read this as a "for that only runs once because it has no
> > iteration second argument".
> This could be done even now in lua 5.4
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