lua-users home
lua-l archive

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


On Tue, Jul 17, 2018 at 4:54 PM John Belmonte <john@neggie.net> wrote:

> I proposed exactly that in 2007 [1], so I'd welcome it.

Which I repeated in 8 years, unaware of your prior work (which led to the message referenced by Roberto earlier).

Unfortunately, Lua is not much like C++ or D. Here is an "official" example from LuaSQL:

-- load driver
local driver = require "luasql.postgres"
-- create environment object
env = assert (driver.postgres())
-- connect to data source
con = assert (env:connect("luasql-test"))
-- reset our table
res = con:execute"DROP TABLE people"
res = assert (con:execute[[
  CREATE TABLE people(
    name  varchar(50),
    email varchar(50)
  )
]])
-- add a few elements
list = {
  { name="Jose das Couves", email="jose@couves.com", },
  { name="Manoel Joaquim", email="manoel.joaquim@cafundo.com", },
  { name="Maria das Dores", email="maria@dores.com", },
}
for i, p in pairs (list) do
  res = assert (con:execute(string.format([[
    INSERT INTO people
    VALUES ('%s', '%s')]], p.name, p.email)
  ))
end
-- retrieve a cursor
cur = assert (con:execute"SELECT name, email from people")
-- print all rows, the rows will be indexed by field names
row = cur:fetch ({}, "a")
while row do
  print(string.format("Name: %s, E-mail: %s", row.name, row.email))
  -- reusing the table of results
  row = cur:fetch (row, "a")
end
-- close everything
cur:close() -- already closed because all the result set was consumed
con:close()
env:close()

Observe that there is only one local variable. The rest are globals. And before somebody says "this is bad code that no one will write", I see this same code copied over and over in production, pretty much verbatim (easily making DB servers or Lua hosts run out of memory).

Here is another example from the same source:

function rows (connection, sql_statement)
  local cursor = assert (connection:execute (sql_statement))
  return function ()
    return cursor:fetch()
  end
end

The variable is local; but it is an upvalue, too, so it can only be collected when the closure is finalised, which means the return value of rows() needs to be a scoped variable. But here is how it is supposed to be used:

env = assert (require"luasql.mysql".mysql())
con = assert (env:connect"my_db")
for id, name, address in rows (con, "select * from contacts") do
  print (string.format ("%s: %s", name, address))
end

That can certainly be rewritten with a scoped declaration, but the point, like in the simpler example above, is that this goes against Lua's entire written corpus and oral tradition. People still find 10-15 year old snippets of code online and argue that "your system is broken" when they do not work, and that is AFTER they are given the latest edition of PiL and pointed to the latest docs. A new obscure way to declare variables isn't likely to fare much better.

This is why, in my opinion, deterministic finalisation should just kick in fully transparently whenever something requiring it is created. It is opting OUT that should be left to the user.

Cheers,
V.