Search code examples
luanumbersrangeconcatenationmetatable

Adding _concat to numbers to create number ranges - am I mad?


Just as a random experiment I'm considering adding a __concat() metamethod to the number metatable (usually a new metatable as numbers don't seem to have metatables by default?).

The idea is that I could do something like 3..5 and get back 3, 4, 5.

I could then have a function foo(tbl, ...) that does something with multiple indexes on a table and call it like foo(tbl, 3..5).

Am I barking mad or does this seem like a viable thing to do?

Rough draft of code (not tested yet):

-- get existing metatable if there is one
local m = getmetatable( 0 ) or {};

-- define our concat method
m.__concat = function( left, right )
    -- note: lua may pre-coerce numbers to strings?
    -- http://lua-users.org/lists/lua-l/2006-12/msg00482.html
    local l, r = tonumber(left), tonumber(right);

    if not l or not r then -- string concat
        return tostring(left)..tostring(right);

    else -- create number range
        if l > r then l, r = r, l end; -- smallest num first?
        local t = {};
        for i = l, r do t[#t+1] = i end;
        return (table.unpack or unpack)(t);

    end
end

-- set the metatable
setmetatable( 0, m );

Additional question: Is there any way for me to populate a ... value by value (to remove the need for a table & unpack in the example above)?


Solution

  • Your idea can be implemented using __call metamethod:

    local mt = debug.getmetatable(0) or {}
    mt.__call = function(a,b)  -- a, b - positive integer numbers
       return (('0'):rep(a-1)..('1'):rep(b-a+1)):match(('()1'):rep(b-a+1))
    end
    debug.setmetatable(0, mt)
    
    -- Example:
    print((3)(5))  -->  3  4  5