lua-users home
lua-l archive

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


сб, 6 июл. 2019 г. в 00:24, Coda Highland <chighland@gmail.com>:
> I'm really not a big fan of that. Not only does that have a ton more overhead thanks to needing to construct extra closures, but it messes with control flow -- you can't, for example, optionally return from the code.
You could follow rule: one enter one exit point. So you will no need
in return. Here return used to live then scope, like break in a loop.
Restrictions are always be. There is a lot of cases where you need no
return at all.

> You have to have the caller inspect the return value and decide whether it needs to return or if it should keep going.
There is no need to inspect return values you can pass all you need in upvalues.
function fn(name)
local f,ff,r1,r2

scope(function(auto) f=auto(){ io.open(name) } -- if it unable to open
file it will leave fn with error
  r1=f:read()
end)
-- file1 closed
scope(function(auto) f=auto(){ io.open "file2" }
  r2=f:read()
end)
-- file2 closed

scope(function(auto) f=auto(){ io.open "file3" }
  scope(function(auto) ff=auto(){ io.open "file 4" } -- nested scopes
  end)
end)

print "if we are here it was no errors and we are done"
end

> At that point, it's barely even syntactic sugar; if you're ALREADY writing a worker function and passing it to another function ("scope" instead of "pcall" but still...) and you have to inspect the return values either way, what have you really gained?
If there was a reference counting we could use meta-method
__unreferenced like __gc to achieve behaviour desired. But there
isn't. So it could be done only with functions.
In lack of __unreferenced we could __gc, but with some clauses.

function for_scope(prm,L)
    if L==nil then
        L={list={}}
        function L.auto(close,msg)
            return function(t)
                if type(t)~='table' then error("need table: {
expression }",2) end
                if t[1] then table.insert(L.list,{ arg=t[1], fn=close
or io.close })
                else
                    if msg=='weak' then return table.unpack(t) end
                    error(msg or t[2] or "no resource",2)
                end
                return table.unpack(t)
            end
        end
        function L.defer(fn) L.auto(fn){true} end
        function L.leave()
            for i=#L.list,1,-1 do
                if L.list[i].fn then
                    local fn=L.list[i].fn
                    L.list[i].fn=false
                    fn(L.list[i].arg)
                end
            end
            L.list={}
        end
        return setmetatable(L,{__gc=function(p) p.leave() end})
    else
        L.leave()
    end
end

for scope in for_scope do
    local f=scope.auto(io.close){ io.open("text.txt","w") }
    scope.defer(function() print"defer" end)
    print"body" -- you can use return and break here
end
-- but need call collectgarbage() to force call __gc in case of errors
and returns

> The advantage of having the syntactical support built into the language itself instead of provided via meta-programming is that it means you can take advantage of all of the other features of the language. I wholly believe that <toclose> serves a purpose that CANNOT be elegantly and efficiently replicated without it. And that's exactly what you should be looking for when adding something to a language.

Lua is small language with simple but powerful syntax. Why we want
worthless increase complexity, instead expressiveness. Why
meta-programming should not be used?
There you need extra speed and very fine stack tuning in files open?
Can you give examples?

> I mean, yeah, I don't think angle brackets are an ideal syntax for it, and "toclose" is something of an awkward name, but everything else about it I think is sound. The only alternative that's come up in all of this bikeshedding that's equivalently expressive is support for a "finally" block, which has its comparative pros and cons. (Weighing the alternatives, I like finally SLIGHTLY better because it gives better control over error handling, but it has bigger syntactical problems and requires more boilerplate for common use cases.)

I think angle brackets if awful. Especially for so trivial operation
such as a releasing resources. I think toclose will born more problem
that it solves.
Lua has coroutines. How you will manage finally blocks there. Also
there are a lot of options how to behave in case of errors, returns or
context switching in finally blocks.