99 ways to program a hex, Part 19: Lua, recursion, closure as callback

Now, instead of passing along data just to be passed to the callback function [1], we can include such data as part of a closure [2] to the function we pass to the do_dump() function.

>
```
#!/usr/bin/env lua
-- ***************************************************************
--
-- Copyright 2010 by Sean Conner. All Rights Reserved.
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Comments, questions and criticisms can be sent to: sean@conman.org
--
-- ********************************************************************
-- Style: Lua 5.1, recursion, closure as callback
function do_dump(fpout,offset,callback)
local line = callback(offset)
if line == nil then return end
fpout:write(
string.format("%08X: ",offset),
line:gsub(".",function(c) return string.format("%02X ",c:byte()) end),
string.rep(" ",3 * (16 - line:len())),
line:gsub("%c","."),
"\n"
)
return do_dump(fpout,offset + 16,callback)
end
-- **********************************************************************
if #arg == 0 then
print("-----stdin-----")
do_dump(io.stdout,0,cb,io.stdin)
else
for i = 1 , #arg do
local f = io.open(arg[1],"r")
io.stdout:write("-----",arg[1],"-----","\n")
do_dump(io.stdout,0,function(offset) return f:read(16) end)
f:close()
end
end
os.exit(0)
```

Here, our function (which is not named, as you don't really need to name functions in Lua [3]) references our open file f, but in order to do so, Lua needs to include a reference to f to the function when said function is passed to do_dump(). It does so by creating what's called a “closure”—think of a closure as both a pointer (or reference) to a function, plus a pointer (or reference) to data that is outside the normal lexical scope [4] of the function.

And why do I pass in the offset when my unnamed (“anonymous”) function doesn't use it? Because it might be useful in some contexts to know where to pull the data (say from a block of memory).

[1] /boston/2012/01/26.1

[2] http://en.wikipedia.org/wiki/Closure_(computer_science)

[3] http://www.lua.org/

[4] http://www.c2.com/cgi/wiki?LexicalScoping

[5] /boston/2012/01/26.1

[6] /boston/2012/01/28.1

Gemini Mention this post

Contact the author