lua-users home
lua-l archive

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


On 19/08/2011 16.25, Tony Finch wrote:
Dirk Laurie<dpl@sun.ac.za>  wrote:

A less trivial example of the proposed syntax extension would be:

     tbl = { ['a','b','c']=good, [4,5,6]=bad, [7,'8','9']=so_so }

	function flatten_keys(template)
		local tbl = {}
		for keys,val in pairs(template) do
			for i,key in ipairs(keys) do
				tbl[key] = val
			end
		end
		return kv
	end

	tbl = flatten_keys{ [{'a','b','c'}] = good,
			    [{4,5,6}] = bad,
			    [{7,'8','9'}] = so_so }

Tony.

Unfortunately I found a rather big problem to your approach. It trades expressiveness for robustness of code. In fact all goes well if the keys in different groups are unique. Whenever you have duplicate keys, things go awry (I'll abbreviate flatten_keys with F):

t = F{
  [{'a', 'b', 'c'}] = 1,
  [{'a'}] = 0,
}

what's the value of t['a'] ?
with my proposal it would have been 0, since the entries would have been processed in order, and the last assignment to t.a would have been t.a = 0 (table constructor guarantee sequential processing).

But in this case the iteration in F among key groups is done using pairs, whose iteration order is unspecified, so it may well be that {'a'} group will be processed before group {'a','b','c'}. In this case the syntax would be misleading. The problem is serious because the iteration order may even change adding another group.

One could argue that this idiom is to be used only with disjoint key groups, but this could lead to brittle code: if someone entered a duplicated key by mistake, it could lead to very hard to find bugs.

A partial solution would be to track already processed keys:


local function MapNTo1( t )
  local map = {}
  local already_seen = {}
  for keys, value in pairs( t ) do
    for _, key in ipairs( keys ) do
      if not already_seen[ key ] then
        already_seen[ key ] = true
        map[ key ] = value
      else
        error( "key already seen: " .. tostring( key ), 2 )
      end
    end
  end
  return map
end



But in a very large map (where my proposal would have been very helpful) this could help only partially:


t = MapNTo1{ -- this is line N
...
-- 50 lines of data
...
} ---> error signaled at line N

In which line lies actually the culprit?


My proposal had some points after all :-)



-- Lorenzo