lua-users home
lua-l archive

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

On Mon, Jul 8, 2019 at 7:14 AM Sergey Kovalev <> wrote:
function for_scope(body)
    local list,res={}
    local function auto(close,msg)
        return function(t)
            if type(t)~='table' then error("need table: { _expression_ }",2) end
            if t[1] then table.insert(list,{ arg=t[1], fn=close or io.close })
                if msg=='weak' then return table.unpack(t) end
                error(msg or t[2] or "no resource",2)
            return table.unpack(t)
    local function defer(fn) auto(fn){true} end
    local ok,err=pcall(function() res={body(auto,defer)} end)
    for i=#list,1,-1 do list[i].fn(list[i].arg) end
    if not ok then
        if type(err)~='string' then error(err,2)
        else error("scope error\nlua: "..err,2) end
    if #res>0 then return res end

function test()
  for t in for_scope,function(auto,defer) -- scope.begin
    local f,err=auto(io.close,"weak") { "test2.txt" }
    defer(function() print "defer" end)
    return auto(){ "readme.txt" }:read()
  end do return table.unpack(t) end -- scope.end

Yes, you can do without "local <toclose>", but I would not call your example readable code. The point of adding features like this to a language is to make programs simpler and easier to understand by increasing the expressive power of the language.

This is a whole lot more readable:

local <toclose> f = assert("test.txt", "r"))
-- do something with f
return value

I think the "<toclose>" facility is a fair tradeoff between added language complexity and expressive power. It's also likely to be much faster because there's no need to create closures, no need to pack or unpack parameter lists, and no need to use 'pcall' or forward the error.