* * * * * 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 . > -- > -- 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). * 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 Sean Conner at sean@conman.org .