seqlua
changeset 37:adf671e3458c
Added section "Motivation" to README
author | jbe |
---|---|
date | Mon Aug 25 02:52:47 2014 +0200 (2014-08-25) |
parents | 4f82d3b3dbd9 |
children | acc53a77fdc9 |
files | README |
line diff
1.1 --- a/README Sun Aug 24 22:32:57 2014 +0200 1.2 +++ b/README Mon Aug 25 02:52:47 2014 +0200 1.3 @@ -1,5 +1,5 @@ 1.4 -seqlua: Extended sequences and iterators in Lua 1.5 -=============================================== 1.6 +seqlua: Extension for handling sequential data in Lua 1.7 +===================================================== 1.8 1.9 This is an experimental package to extend Lua in the following manner: 1.10 1.11 @@ -15,6 +15,122 @@ 1.12 ``__ipairs`` metamethod takes precedence over ``__index``, while the 1.13 ``__len`` metamethod is never used. 1.14 1.15 +Metamethod handling in detail is explained in the last section 1.16 +("Respected metamethods") at the bottom of this README. 1.17 + 1.18 + 1.19 + 1.20 +Motivation 1.21 +---------- 1.22 + 1.23 +Sequential data (such as arrays or streams) is often represented in two 1.24 +different ways: 1.25 + 1.26 +* as an ordered set of values (usually implemented as an array in other 1.27 + programming languages, or as a sequence in Lua: a table with numeric keys 1.28 + {1..n} associated with a value each), 1.29 +* as some sort of data stream (sometimes implemented as a class of objects 1.30 + providing certain methods, or as an iterator function in Lua: a function that 1.31 + returns the next value with every call, where nil indicates the end of the 1.32 + stream). 1.33 + 1.34 +Quite often, when functions work on sequential data, it shouldn't matter in 1.35 +which form the sequential data is being provided to the function. As an 1.36 +example, consider a function that is writing a sequence of strings to a file. 1.37 +Such function could either be fed with an array of strings (a table with 1.38 +numeric keys in Lua) or with a (possibly infinite) stream of data (an iterator 1.39 +function in Lua). 1.40 + 1.41 +A function in Lua that accepts a table, might look like as follows: 1.42 + 1.43 + function write_lines(lines) 1.44 + for i, line in ipairs(lines) do 1.45 + io.stdout:write(line) 1.46 + io.stdout:write("\n") 1.47 + end 1.48 + end 1.49 + 1.50 +In contrast, a function in Lua that accepts an iterator function would have to 1.51 +be implemented differently: 1.52 + 1.53 + function write_lines(get_next_line) 1.54 + for line in get_next_line do 1.55 + io.stdout:write(line) 1.56 + io.stdout:write("\n") 1.57 + end 1.58 + end 1.59 + 1.60 +If one wanted to create a function that accepts either a sequence in form of a 1.61 +table or an iterator function, then one might need to write: 1.62 + 1.63 + function write_lines(lines) 1.64 + local iter1, iter2, iter3 1.65 + if type(lines) == "function" then 1.66 + iter1 = lines 1.67 + else 1.68 + iter1, iter2, iter3 = ipairs(lines) 1.69 + end 1.70 + for i, line in iter1, iter2, iter3 do 1.71 + io.stdout:write(line) 1.72 + io.stdout:write("\n") 1.73 + end 1.74 + end 1.75 + 1.76 +Obviously, this isn't something we want to write in every function that accepts 1.77 +sequential data. Therefore, we usually decide for one of the two first forms 1.78 +and therefore disallow the other possible representation of sequential data to 1.79 +be passed to the function. 1.80 + 1.81 +This extension, however, modifies Lua's ``ipairs`` statement in such way that 1.82 +it automatically accepts either a table or an iterator function as argument. 1.83 +Thus, the first of the three functions above will accept both (table) sequences 1.84 +and (function) iterators. 1.85 + 1.86 +In addition to the modification of ``ipairs``, it also provides C functions and 1.87 +macros to iterate over values in the same manner as a generic loop statement 1.88 +with ``ipairs`` would do. 1.89 + 1.90 +Note that this extension doesn't aim to supersede Lua's concept of iterator 1.91 +functions. While metamethods (see section "Respected metamethods" below) may be 1.92 +used to customize iteration behavior on values, this extension isn't thought to 1.93 +replace the common practice to use function closures as iterators. Consider the 1.94 +following example: 1.95 + 1.96 + local result = sql_query("SELECT * FROM actor ORDER BY birthdate") 1.97 + write_lines(result:get_column_entries("name")) 1.98 + 1.99 +The ``get_column_entries`` method can return a simple function closure that 1.100 +returns the next entry in the "name" column (returning ``nil`` to indicate the 1.101 +end). Such a closure can then be passed to another function that iterates 1.102 +through a sequence of values by invoking ``ipairs`` with the general for-loop 1.103 +(as previously shown). 1.104 + 1.105 +Where desired, it is also possible to use metamethods to customize iteration 1.106 +behavior. Consider: 1.107 + 1.108 + function process_row(database_row) 1.109 + -- some function 1.110 + end 1.111 + local result = sql_query("SELECT * FROM actor") 1.112 + process_row(result) -- without writing :rows() or similar 1.113 + 1.114 +This extension, however, doesn't respect the ``__len`` metamethod due to the 1.115 +following reasons: 1.116 + 1.117 +* An efficient implementation seems to be impossible, where 1.118 + ``for i, v in ipairs(tbl) do ... end`` does neither create a closure 1.119 + nor repeatedly evaluate ``#tbl``. 1.120 +* Respecting ``__len`` could be used to implement sparse arrays, but this would 1.121 + require iterating functions to expect ``nil`` as a potential value. This may 1.122 + lead to problems because ``nil`` is usually also used to indicate the absence 1.123 + of a value. 1.124 + 1.125 +If such behavior is desired, though, it can still be implemented through the 1.126 +``__ipairs`` metamethod. 1.127 + 1.128 +Unless manually done by the user in the ``__ipairs`` metamethod, this extension 1.129 +never creates any closures or other values that need to be garbage collected. 1.130 + 1.131 1.132 1.133 Lua part of the library 1.134 @@ -94,6 +210,7 @@ 1.135 -- prints: alpha,beta 1.136 1.137 1.138 + 1.139 C part of the library 1.140 --------------------- 1.141 1.142 @@ -144,6 +261,7 @@ 1.143 ``seqlua_iterloopauto`` is used. 1.144 1.145 1.146 + 1.147 Respected metamethods 1.148 --------------------- 1.149