lua-users home
lua-l archive

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


Am 12.05.2013 08:29 schröbte Dirk Laurie:
A subtype is a class of objects that share the same metatable, in
particular when the objects belong to a type of which the metatable
can only be set via the debug library.

I have written a module `subtype.c` of which the complete code is this:

/* A subtype is a standard Lua type with a subtype-specific metatable.

    subtype = require"subtype"

    bits = subtype('number',bits_mt)
    j = bits(10)
    print(j,type(j),getmetatable(j)==bits_mt)
0x0000000a     number  true
    i=10
    print(i,type(i),getmetatable(i))
10    number   nil


    local ID = {}  -- private unique key
    local orig_type = type

    local function isproxy( v )
      return orig_type( v ) == "table" and rawget( v, ID )
    end
    local function unproxy( proxy )
      return table.unpack( proxy[ ID ], 1, 3 )
    end

    local meta_template = {
      __tostring = function( self )
        local v, mt = unproxy( self )
        local tos = mt.__tostring
        if tos ~= nil then
          return tos( v )
        end
        return tostring( v )
      end,
      __len = function( self )
        local v, mt = unproxy( self )
        local len = mt.__len
        if len ~= nil then
          return len( v )
        end
        return #v
      end,
      -- more delegating metamethods ...
    }

    local function subtype( t, mt )
      local dmt = { __metatable = mt }
      for k,v in pairs( meta_template ) do
        dmt[ k ] = v
      end
      return function( v )
        local o = { [ID]={ v, mt, t } }
        return setmetatable( o, dmt )
      end
    end

    _G.type = function( v )
      if isproxy( v ) then
        local _, _, t = unproxy( v )
        return t
      else
        return orig_type( v )
      end
    end

    -- example code
    local bits_mt = {
      __tostring = function( self )
        return string.format( "0x%08x", self )
      end,
    }
    local bits = subtype( 'number', bits_mt )
    local j = bits( 10 )
    print( j, type( j ), getmetatable( j ) == bits_mt )
    local i = 10
    print( i, type( i ), getmetatable( i ) )


There are holes however (e.g. no automatic coercion string <-> number, type checking via Lua C API) ...


    utf8 = subtype('string',utf8_mt)
    t = "skêr"
    s = utf8(t)
    print(#t,type(t),getmetatable(t).__index==string)
5    string   true
    print(#s,type(s),getmetatable(s).__index==string)
4    string   false

I.e. the effect is as if one said "debug.setmetatable(j,bits_mt)"
and "debug.setmetatable(s,utf8_mt)" but without affecting
other numbers and strings.
  */

That's right, it consists of only a comment. The reason is that
I have only a foggy notion of what to do next. Clearly the real
object must be a userdata wrapping a single Lua TValue. Also
the built-in type function would need to be replaced. But it seems
to be impossible to do what I want in the C API, one would need
to use lobject.h.

For what?

Philipp