setmetatable vs debug.setmetatable?

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

setmetatable vs debug.setmetatable?

Petite Abeille
Hello,

For the record:

% lua -v
Lua 5.1.2  Copyright (C) 1994-2007 Lua.org, PUC-Rio

With setmetatable, one can assign a metatable per table instance. One the other hand, debug.setmetatable seems to assign a metatable per object type, not object instance, e.g.:

local aFunction = function() end

debug.setmetatable( aFunction, { __len = function() return 1 end } )

print( #aFunction )

>       1

Unfortunately, it seems like all function instances share the same metatable:

local anotherFunction = function() end

debug.setmetatable( anotherFunction, { __len = function() return 2 end } )

print( #aFunction, #anotherFunction )

>       2       2

This even though the documentation states that debug.setmetatable is "for the given object", not object type:

"Sets the metatable for the given object to the given table (which can be nil)."

Bug or feature?

In any case, how to get around such conundrum and properly simulate one metatable per function instance?

Perhaps one could try using a function environment, which can be set per function instance:

local aFunction = function() end

debug.setmetatable( aFunction, { __len = function( self ) return getfenv( self ):__len() end } )

setfenv( aFunction, { __len = function() return 1 end } )

local anotherFunction = function() end

setfenv( anotherFunction, { __len = function() return 2 end } )

print( #aFunction, #anotherFunction )

>       1       2

Is there a more straightforward way?

Thanks in advance.

Cheers,

PA.


Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs debug.setmetatable?

Duncan Cross
Wrap the function as the __call metamethod in a table?

On 8/3/07, PA <[hidden email]> wrote:
> Hello,
>
> For the record:
>
> % lua -v
> Lua 5.1.2  Copyright (C) 1994-2007 Lua.org, PUC-Rio
>
> With setmetatable, one can assign a metatable per table instance. One
> the other hand, debug.setmetatable seems to assign a metatable per
> object type, not object instance, e.g.:
>
> local aFunction = function() end
>
> debug.setmetatable( aFunction, { __len = function() return 1 end } )
>
> print( #aFunction )
>
>  >       1
>
> Unfortunately, it seems like all function instances share the same
> metatable:
>
> local anotherFunction = function() end
>
> debug.setmetatable( anotherFunction, { __len = function() return 2 end
> } )
>
> print( #aFunction, #anotherFunction )
>
>  >       2       2
>
> This even though the documentation states that debug.setmetatable is
> "for the given object", not object type:
>
> "Sets the metatable for the given object to the given table (which can
> be nil)."
>
> Bug or feature?
>
> In any case, how to get around such conundrum and properly simulate one
> metatable per function instance?
>
> Perhaps one could try using a function environment, which can be set
> per function instance:
>
> local aFunction = function() end
>
> debug.setmetatable( aFunction, { __len = function( self ) return
> getfenv( self ):__len() end } )
>
> setfenv( aFunction, { __len = function() return 1 end } )
>
> local anotherFunction = function() end
>
> setfenv( anotherFunction, { __len = function() return 2 end } )
>
> print( #aFunction, #anotherFunction )
>
>  >       1       2
>
> Is there a more straightforward way?
>
> Thanks in advance.
>
> Cheers,
>
> PA.
>
>

Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs debug.setmetatable?

Petite Abeille

On Aug 03, 2007, at 14:24, Duncan Cross wrote:

Wrap the function as the __call metamethod in a table?

Cunning... :P

But then... one cannot (re)define the __len metamethod :(


Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs debug.setmetatable?

Duncan Cross
True, I forgot about that. Is there any chance you could register a C
function that uses the API to give you a "dummy" full userdata (one
byte long or something) instead of a table, and set the metatable on
that instead?

On 8/3/07, PA <[hidden email]> wrote:
>
> On Aug 03, 2007, at 14:24, Duncan Cross wrote:
>
> > Wrap the function as the __call metamethod in a table?
>
> Cunning... :P
>
> But then... one cannot (re)define the __len metamethod :(
>
>

Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs debug.setmetatable?

Tony Finch
In reply to this post by Petite Abeille
On Fri, 3 Aug 2007, PA wrote:
>
> With setmetatable, one can assign a metatable per table instance. One the
> other hand, debug.setmetatable seems to assign a metatable per object type,
> not object instance, e.g.:

See paragraph 5 of section 2.8 of the reference manual. Only tables and
userdata have per-value metatables. The other metatables are per-type.

Tony.
-- 
f.a.n.finch  <[hidden email]>  http://dotat.at/
IRISH SEA: SOUTHERLY, BACKING NORTHEASTERLY FOR A TIME, 3 OR 4. SLIGHT OR
MODERATE. SHOWERS. MODERATE OR GOOD, OCCASIONALLY POOR.

Reply | Threaded
Open this post in threaded view
|

setmetatable vs setfenv consolidation? (was Re: setmetatable vs debug.setmetatable?)

Petite Abeille
Hello,

On Aug 03, 2007, at 14:32, Tony Finch wrote:

See paragraph 5 of section 2.8 of the reference manual. Only tables and
userdata have per-value metatables. The other metatables are per-type.

Yes, very unfortunate discrepancy...

That said, now that in Lua 5.1 any object can potentially have its very own metatable, wouldn't it make some kind of sense to drop getfenv and setfenv altogether and extend getmetatable/setmetatable to properly handle functions in addition to tables?

After all, a table metatable or a function environment seems to be very much alike... any reason(s) not to make them the same?

setmetabletable( aFunction, aMetatable ) = setfenv( aFunction, anEnvironment )





Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs setfenv consolidation? (was Re: setmetatable vs debug.setmetatable?)

Stefan Brantschen

On 3 Aug 2007, at 14:47, PA wrote:

After all, a table metatable or a function environment seems to be very much alike... any reason(s) not to make them the same?

setmetabletable( aFunction, aMetatable ) = setfenv( aFunction, anEnvironment )

Much alike?

-- metatable: place to redefine behavior
-- environment: global storage space

IMHO, I'd think less about how to change Lua, but how to use what's available... :-)

With regards
-- Stefan





Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs debug.setmetatable?

Thomas Lauer-3
In reply to this post by Duncan Cross
"Duncan Cross" <[hidden email]> wrote:

> True, I forgot about that. Is there any chance you could register a C
> function that uses the API to give you a "dummy" full userdata (one
> byte long or something) instead of a table, and set the metatable on
> that instead?

The (undocumented) function newproxy() might be the ticket. Search the
list archives.

> On 8/3/07, PA <[hidden email]> wrote:
> >
> > On Aug 03, 2007, at 14:24, Duncan Cross wrote:
> >
> > > Wrap the function as the __call metamethod in a table?
> >
> > Cunning... :P
> >
> > But then... one cannot (re)define the __len metamethod :(

-- 
cheers  thomasl

web : http://thomaslauer.com/start


Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs debug.setmetatable?

Luis Carvalho-2
> > True, I forgot about that. Is there any chance you could register a C
> > function that uses the API to give you a "dummy" full userdata (one
> > byte long or something) instead of a table, and set the metatable on
> > that instead?
> 
> The (undocumented) function newproxy() might be the ticket. Search the
> list archives.

Try this:

newf = function(f, l)
  local p = newproxy(true)
  local mt = getmetatable(p)
  mt.__call = function(_, ...) return f(...) end
  mt.__len = function() return l end
  return p
end

> f1 = newf(math.cos, 1)
> print(#f1) --> 1
> print(f1(1)) --> 0.54030230586814
> f2 = newf(function(x,y) return x+y end, 2)
> print(#f2) --> 2
> print(f2(2,3)) --> 5

Cheers,
Luis.

-- 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos 

-- 
Luis Carvalho
Applied Math PhD Student - Brown University
PGP Key: E820854A <[hidden email]>

Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs debug.setmetatable?

David Dunham
In reply to this post by Tony Finch

On 3 Aug 2007, at 05:32, Tony Finch wrote:

See paragraph 5 of section 2.8 of the reference manual. Only tables and
userdata have per-value metatables. The other metatables are per-type.

Hmm, I think I just figured out what went wrong yesterday.

I was trying to create a Lua interface for a couple of C++ classes. I was using lightuserdata to represent the C++ pointer. The first one worked fine. Adding the second C++ class broke the first. I guess what I was doing was setting the metatable for any lightuserdata.

(Yes, I know there are things like toLua out there. I was working through this by hand to try to really understand things. Which obviously I still don't!)

David Dunham       Development Manager
+1 206 926 5722      GameHouse Studios



Reply | Threaded
Open this post in threaded view
|

Re: setmetatable vs setfenv consolidation? (was Re: setmetatable vs debug.setmetatable?)

Petite Abeille
In reply to this post by Stefan Brantschen

On Aug 03, 2007, at 15:18, Stefan Brantschen wrote:

-- metatable: place to redefine behavior
-- environment: global storage space

environment: metatable.__index ?

Same difference, no?

IMHO, I'd think less about how to change Lua, but how to use what's available... :-)

Good point, good point, I shall ponder that wisdom :)

That said, in the case of environment vs. metatable, there is perhaps too many ways to express the same thing?

In any case, going back to my cave :P

Cheers,

PA.


Reply | Threaded
Open this post in threaded view
|

RE: setmetatable vs setfenv consolidation? (was Re: setmetatable vsdebug.setmetatable?)

Jerome Vuarand-2
PA wrote:
>> IMHO, I'd think less about how to change Lua, but how to use what's
>> available... :-)
> 
> Good point, good point, I shall ponder that wisdom :)
> 
> That said, in the case of environment vs. metatable, there is perhaps
> too many ways to express the same thing? 

The fact that userdata have both a metatable and an environment allows
to easily have one of the two on a per object basis, and the other on a
per class basis. It's not necessary, but very useful.