[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: To-be-close confusion...
- From: Sean Conner <sean@...>
- Date: Sat, 15 Jun 2019 18:03:34 -0400
It was thus said that the Great Paul Ducklin once stated:
>
> It’s also not that clear how to use it, given that the manual says that
> to-be-closed variables are constants. My thought is that seems like a
> great feature for things like files and sockets as a way of recovering
> cleanly from errors - but I’ve never thought of files and sockets as
> “constant variables” because they are all about side effects and
> continuously changing state.
In Lua, variables and values are two distinct things. In Lua, I can do:
x = 'one'
x = 2
x = { 'three' }
x = io.stdout
x = print
That's because a variable (in this case, 'x') is a name to which you can
attach a value---values have types, not variables. When you do:
local <toclose> x = ...
This makes the variable 'x' constant---you cannot change what value it
has, but the value itself may change (a table, a userdata, etc).
> In short: why do I need <toclose>, what do I do with it, and how do I use
> it properly?
Given the following example code:
local function readfile(name)
local <toclose> f = io.open(name)
if not f then return end
local res = {}
res.date = parse_date(f)
if not res.date then return end
res.name = parse_name(f)
if not res.name then return end
res.data = parse_data(f)
if not res.data then return end
return res
end
Each place where we return, the file f will be closed (because it's marked
as <toclose> and we're leaving the current scope). There's nothing
inherenetly *wrong* if you don't have <toclose>, as eventually the file will
be closed when garbage collection kicks in, but that might be awhile, and in
the meantime, the number of open files you can have is one less, which could
cause an open failure down the road. To solve this pre-Lua 5.4, you have to
explicitely close the file along each error path:
local function readfile(name)
local f = io.open(name)
if not f then return end
local res = {}
res.date = parse_date(f)
if not res.date then
f:close()
return
end
res.name = parse_name(f)
if not res.name then
f:close()
return
end
res.data = parse_data(f)
if not res.data then
f:close()
return
end
f:close()
return res
end
Or perhaps this:
local function readfile(name)
local function readdata(f,res)
res.date = parse_date(f)
if not res.date then return false end
res.name = parse_name(f)
if not res.name then return false end
res.data = parse_data(f)
return res.data ~= nil
end
local f = io.open(name)
local res = {}
local good = readdata(f,res)
f:close()
if good then return res end
end
You generally want to use <toclose> for resources other than memory where
waiting for garbage collection may be too long. And remember, this is a
contrived example. Imaging two files being processed, or the function being
longer, or more possible error paths (or all the above).
This if this as coroutines---you can go a very long time without having to
understand, or even use, coroutines, but yet they're there for when you need
them.
-spc