* * * * *

    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: [email protected]
> --
> -- ********************************************************************
>
> -- 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).

* Part 18: Lua, recursion, callback [5]
* Part 20: C89, const correctness, assertive, system calls [6]

[1] gopher://gopher.conman.org/0Phlog: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] gopher://gopher.conman.org/0Phlog:2012/01/26.1
[6] gopher://gopher.conman.org/0Phlog:2012/01/28.1

Email author at [email protected]