lua-users home
lua-l archive

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

On Friday 28 January 2011 17:33:16 Petite Abeille wrote:
> On Jan 28, 2011, at 9:40 PM, Steve Litt wrote:
> > I hope you enjoy it, and please be gentle when you tell me all the things
> > I did wrong with it. :-)
> Nothing fundamentally wrong per say, but... just wondering... isn't it a
>  bit overkill? :))

Might be. I'll have to do timing tests to see whether it saps performance.

As far as programming overkill, no. The application programmer just pubs a 
filename and maybe a 4 line callback function in a table, passes it on in, and 
gets back only the needed lines, while line numbers stay intact for error 

> My 2¢...
> >  function relevant_lines(tab)
> Why a table as a parameter? What's wrong with explicit parameters? E.g.:
> relevant_lines( aFile, is_relevant, tweak )

That's how I did it the first time. Trouble is, I can't guess what logic the 
programmer might use in selecting valid lines. There could be fascinating 
break logic, or, who knows. Me -- I'd probably try to steer clear from putting 
actual application logic in the callbacks, but by putting all info in the 
table this tool can be adapted in any imaginable way, and probably some 
unimaginable ones too.

> > if tab == nil then .. io.stderr:write... os.exit...
> Look into  assert(), e.g.:
> assert( function() return type( tab ) == 'table' end(), 'Expected a table,
>  got ' .. type( tab ) .. ' instead' )

Good idea. I forgot about the concat operator.

> > if .. elseif... elseif... else
> A common idiom if you have many such simple condition is to use a table
>  instead, e.g.:
> -- define a mapping between type and function
> aMap = { string = function( aValue ) return aValue , 'rb' ), ... }
> -- lookup a function
> aFunction = aMap[ type( aValue ) ]
> -- invoke it
> aFunction( aValue )
> > elseif type(tab.file) == "userdata" then
> Perhaps try io.type(obj) == 'file' instead

Thanks! I was looking for something like that. That definitely goes in the 
next time I modifiy this thing.
> >  if not tab.is_relevant then
> Another handy idiom to provide default values:
> tab.is_relevant = tab.is_relevant or function() ... end
> > tab.this_line_text = ...
> What about simply passing the value directly to your is_relevant()
>  function? Is that shared table really adding anything?

It adds a lot of flexibility. You're guaranteed that absolutely anything is 
available to is_relevant() and tweak(). They can communicate with each other. 
They can even leave Easter Eggs for the program after all lines are iterated 
(counts, totals, etc). Like I said, I probably wouldn't use it that way, but 
it's available.

> All in all, wouldn't it be clearer to simply say what you mean? E.g.:
> for aLine in aFile:lines() do
>   if Accept( aLine ) then
>     Transform( aLine )
>   end
> end

Yes and no. I assume here you mean instead of the relevant_lines() iterator 
maker. It's obviously simpler on the face of it, but maybe not so much when 
you have to add "skip all blank lines and lines beginning with %s*#" to 
Accept(). The point of it is to blow off obviously bad lines very early so you 
needn't even consider them in Accept().

Also, I think my main point in putting in tweak() (and therefore tweak() may 
be a very bad name for it) was to facilitate more complex break logic when 
rejecting lines from further scrutiny. I haven't thought it all through yet.

Thanks. You've given me a lot to think about.

Steve Litt
Recession Relief Package