lua-users home
lua-l archive

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


Chris Marrin wrote:

> It would be easy to write such things, of course, by doing type(),
> checking against nil and throwing errors. But is there any "standard"
> way to do this? I have not been able to find anything...

I don't know of a standard way. Below is the way that I do it for a
couple of my projects (5.0). Note that I register my own types and use
Object.type() rather than the built-in type(). But the system below
doesn't require the registration of types - just change 'typefunc or
Object.type' to 'typefunc or type'. I usually use Object.types3()
because it results in shorter argument lists.

-- ------------------------------------------------------------------
-- Returns a string with a comma-separated list of the types of the
-  elements of array 'a'. This is useful for functions that do
-- different things based on the type of the arguments.
--
-- 'typefunc' should return a string if the type is found, nil
-- otherwise. If not given, 'typefunc' will be Object.type.
--
-- For example:
--    function fun(...)
--       local argtypes = Object.types(arg)
--       if     argtypes == 'number'        then ....
--       elseif argtypes == 'string,number' then ...
--       elseif argtypes == 'string,string' then ...
--       end
--    end
--
function Object.types(args, typefunc)
   typefunc = typefunc or Object.type

   if table.getn(args) == 0 then
      return ''
   end

   local s = typefunc(args[1])

   for i = 2, table.getn(args) do
      s = s .. ',' .. typefunc(args[i])
   end

   return s
end   -- Object.types()

-- ------------------------------------------------------------------
-- Like Object.types, but each typename is shortened to three
-- letters.
function Object.types3(args, typefunc)
   local names = Object.types(args, typefunc)

   return string.gsub(names,
                      '(%a*)',
                      function (s) return string.sub(s, 1, 3) end)
end   -- Object.types3()

Below is an example using it. 'bstring' is one of the registered types
(a string of bits that can be manipulated much like Lua strings). Note
that the actual code has longer lines so that the arguments can easily
be seen. I wrapped the 'then' clauses so they'd fit in a plain text email.

-- ------------------------------------------------------------------
-- Transmits a message on the channel.
--
-- The canonical form for message transmission is:
--   self:transmit(bits, syncbits)
-- where each argument is bstring object. This will transmit the
-- given 'bits' using sync pattern 'syncbits'.
--
-- The other forms will convert data strings into bit strings before
-- calling the canonical form. The current sync pattern at index 1
-- is used whenever no sync pattern is indicated. Transmission data
-- should be specified before sync patterns.
--
function Channel:transmit(...)
   local argtype = Object.types3(arg)

   local tx    = function (databits, syncbits)
                    return self:transmit(databits, syncbits)
                 end
   local newbs = bstring.newdata

   if argtype == 'bst,bst' then
      return idmmodem.transmit(self.radio,
                               arg[2]:data(),  -- Sync pattern first.
                               arg[2]:len(),
                               arg[1]:data(),
                               arg[1]:len())
   -- These are easier to read when each is on its own line:
   elseif argtype == 'bst' then
      return tx(arg[1], self:getSync(1).bits)
   elseif argtype == 'bst,num' then
      return tx(arg[1], self:getSync(arg[2]).bits)
   elseif argtype == 'bst,str' then
      return tx(arg[1], newbs(arg[2]))
   elseif argtype == 'bst,str,num' then
      return tx(arg[1], newbs(arg[2], arg[3]))
   elseif argtype == 'str' then
      return tx(newbs(arg[1]), self:getSync(1).bits)
   elseif argtype == 'str,bst' then
      return tx(newbs(arg[1]), arg[2])
   elseif argtype == 'str,num' then
      return tx(newbs(arg[1], arg[2]), self:getSync(1).bits)
   elseif argtype == 'str,num,bst' then
      return tx(newbs(arg[1], arg[2]), arg[3])
   elseif argtype == 'str,num,num' then
      return tx(newbs(arg[1], arg[2]), self:getSync(arg[3]).bits)
   elseif argtype == 'str,num,str' then
      return tx(newbs(arg[1], arg[2]), newbs(arg[3]))
   elseif argtype == 'str,num,str,num' then
      return tx(newbs(arg[1], arg[2]), newbs(arg[3], arg[4]))
   elseif argtype == 'str,str' then
      return tx(newbs(arg[1]), newbs(arg[2]))
   elseif argtype == 'str,str,num' then
      return tx(newbs(arg[1]), newbs(arg[2], arg[3]))
   else
      error ("unsupported argument types '" .. argtype .. "'")
   end
end   -- Channel:transmit()



-- 
--__-__-____------_--_-_-_-___-___-____-_--_-___--____
Doug Rogers - ICI - V:703.893.2007x220 www.innocon.com
-_-_--_------____-_-_-___-_--___-_-___-_-_---_--_-__-_