Displaying All Properties of an Object

I’m learning Corona SDK and Lua, and was wondering if one could print out all the properties of a display object. It’s just a table isn’t it? I thought one could do:

local ball = display.newImage( "orange\_clear\_ball\_75.png" )  
ball.x = math.random( display.contentWidth ) --Just putting it somewhere on the screen for fun  
ball.y = -ball.contentHeight + 150  
  
for key,value in pairs(ball) do  
 print( key, value )  
end  

But the output are just some memory addresses (of something called “proxy userdata”, and the class table):

_proxy userdata: 0x1bd371f4
_class table: 0x17d687f0

Curious minds want to know. :slight_smile:

Eric [import]uid: 128346 topic_id: 23378 reply_id: 323378[/import]

userdata is the data that is created from the C/C++ wrapper to lua and you cannot change that, that would provide the generic x, y, height, width etc properties of the object and hence aptly named _proxy.

before you jump to but x and y are already accessible, the proxy is used to set the metatable so that a function like

 object:x(5)  

can be called as

 object.x = 5  

_class is self explanatory, not things that you want to mess/change, if you change the metatable, you can make the display objects into just ordinary tables. [import]uid: 3826 topic_id: 23378 reply_id: 93659[/import]

That’s very interesting.
But I don’t want to change anything, I just want to see what’s “inside” an object - what it’s properties are. Isn’t there some way yo programmatically list them?
In other words, if something (an object, such as a display object) is a table, isn’t there some way to see what’s in the table?
Why is my little program just listing memory addresses? [import]uid: 128346 topic_id: 23378 reply_id: 93660[/import]

Have you heard of recursion? if the table is an ordinary table, you can dump the contents of that table with recursion.

it prints the memory address because that is how tables are displayed in lua. [import]uid: 3826 topic_id: 23378 reply_id: 93661[/import]

Yes, it’s been eons since I played with recursion though. It’s basically a function calling itself, right? So a common example is calculating the Fibonacci sequence.
I wouldn’t know how to do it offhand to print out a table.

When I say a table I mean for example, properties of a display object such as alpha, height, isVisible, etc.

When you say “the memory address because that is how tables are displayed in lua”, are you talking about metatables? Because I’ve never seen any Lua tables where the keys are memory addresses. Or do you mean that’s what they *are* underneath?

Thanks [import]uid: 128346 topic_id: 23378 reply_id: 93663[/import]

I’ve posted a deep debug function as part of the source for my simplified XML extension:

https://developer.anscamobile.com/code/much-improved-dump-function-and-xml-simplify

Take the debug function from the main file and see if that suits your needs.

Matt [import]uid: 8271 topic_id: 23378 reply_id: 93714[/import]

haracebury, I guess it’s the dump function in that XML code you’re talking about? I see it also uses the pairs() function, like I was trying to use. It also uses recursion like JayantV mentioned. It might work but is beyond my time/ability to untangle it and make use of. Thanks though.

In the meantime I stumbled across an interesting bit of code at http://www.lua.org/demo.html
One of the sample programs is called “globals”, and it prints out the whole huge table of _G:

-- globals.lua  
-- show all global variables  
  
local seen={}  
  
function dump(t,i)  
 seen[t]=true  
 local s={}  
 local n=0  
 for k in pairs(t) do  
 n=n+1 s[n]=k  
 end  
 table.sort(s)  
 for k,v in ipairs(s) do  
 print(i,v)  
 v=t[v]  
 if type(v)=="table" and not seen[v] then  
 dump(v,i.."\t")  
 end  
 end  
end  
  
dump(\_G,"")  

Educational to look through the output in itself, especially when you try it in the Corona SDK environment…

Anyway, I modified the “globals” program to look at a display object
local ball = display.newImage( “orange_clear_ball_100.png” )

and got this:

_class
__index
addBehavior
hasBehavior
initProxy
removeBehavior
_proxy

Not sure what it means - these are not properties one has access to normally, from what I can tell of the API, but it’s interesting nonetheless. At least it’s not just memory addresses.

Eric

[import]uid: 128346 topic_id: 23378 reply_id: 94181[/import]

Actually, I meant you should just call my dump function and it’ll tell you everything in your object. [import]uid: 8271 topic_id: 23378 reply_id: 94234[/import]

OK, I tried that, and it just gets stuck in an infinite loop, printing “index.__” endlessly. (Ctrl-c wouldn’t break it in the Terminal, and the simulator had to be force-quit). Like I said, I’m new at this (“know enough to be dangerous”), so it would take me too long to untangle the code.

Here’s what I tried:

[code]
local ball = display.newImage( “orange_clear_ball_100.png” )
ball.x = math.random( display.contentWidth )
ball.y = -ball.contentHeight + 300

function dump(t, indent)
local notindent = (indent == nil)
if (notindent) then print(’-----dump-----’); indent=’{}’; end
if (t and type(t) == ‘table’) then
for k, v in pairs(t) do
if (type(k) ~= ‘number’) then
print(indent … ‘.’ … k … ’ = ’ … tostring(v))
if (indent) then
dump(v, indent…’.’…k)
end
end
end
for i=1, #t do
print(indent … ‘[’ … i … ‘] = ’ … tostring(t[i]))
dump(t[i], indent … ‘[’ … i … ‘]’)
end
end
if (notindent) then print(’-----dump-----’); end
end

print(’\n\nThe tables as originally accessed:\n\n’)

dump(ball)

[/code] [import]uid: 128346 topic_id: 23378 reply_id: 94498[/import]

Ok, here’s a simple form of the dump function:

[lua]function dump(path,t,depth)
for k,v in pairs(t) do
print(path…k…’ = ‘…v)
if (type(v) == “table”) then
dump(path…k…’.’,v,depth-1)
end
end
end
dump(‘ball.’,ball,5)[/lua]

That should iterate down to a level of 5 child tables and then exit.

Please bear in mind that I’ve written that off the top of my head and might need a little love to work right, but the concept is solid. [import]uid: 8271 topic_id: 23378 reply_id: 94501[/import]

That certainly is simpler.
Got an error: “attempt to concatenate local ‘v’ (a userdata value)”
So was able to figure out It needed v in the print function to be tostring(v) in order to run, but it still just prints out infinite

… __index.__index.__index.__index.__index.__index.__index.__index.__index._ …

and crashes the simulator.

I tried it with the _G object to see if the object made a difference. Same thing.

Sorry, my love isn’t knowledgeable enough yet. :slight_smile: [import]uid: 128346 topic_id: 23378 reply_id: 94508[/import]

Sorry, line 3 should be:\
[lua]print(path…k…’ = '…tostring(v))[/lua] [import]uid: 8271 topic_id: 23378 reply_id: 94515[/import]

Yes, as you can see in my response above, that’s what I tried. It fixes the error, but
it loops infinitely, like the dump function. [import]uid: 128346 topic_id: 23378 reply_id: 94524[/import]

Yup, cos I left out one thing:
[lua]Line 1.5: if depth <= 0) then return end[/lua]
It was a long day! [import]uid: 8271 topic_id: 23378 reply_id: 94691[/import]

OK, that seems to be working better. It’s limited so the recursion doesn’t go crazy I guess.

Just seems to repeat
ball._class.removeBehavior = function: 0x15c51460
ball._class.initProxy = function: 0x15c47300
ball._class.hasBehavior = function: 0x15c47320
ball._class.addBehavior = function: 0x15c51440
ball._class.__index = table: 0x15cd4f20

But I was hoping there was some easy to see all properties or functions for an object, like the ones you see in the API, but obviously I’m in over my head.

I guess this is operating at a higher level, like a metatable?

Here’s the program now and the output, for the edification of anyone interested.

-- Simple table dump function, courtesy of horacebury. I wanted to see what tables are in an object  
-- 3/19/12  
-- (Uses my ball object)  
--   
ball = display.newImage( "orange\_clear\_ball\_100.png" )  
ball.x = math.random( display.contentWidth )  
ball.y = -ball.contentHeight + 300  
  
function dump(path,t,depth)  
 for k,v in pairs(t) do  
 print(path..k..' = '..tostring(v))  
 if (type(v) == "table") then  
 if depth \<= 0 then return end  
 dump(path..k..'.',v,depth-1)  
 end  
 end  
end  
dump('ball.',ball,5)  

OUTPUT:

ball._proxy = userdata: 0x15c3dae4
ball._class = table: 0x15cd4f20
ball._class.removeBehavior = function: 0x15c51460
ball._class.initProxy = function: 0x15c47300
ball._class.hasBehavior = function: 0x15c47320
ball._class.addBehavior = function: 0x15c51440
ball._class.__index = table: 0x15cd4f20
ball._class.__index.removeBehavior = function: 0x15c51460
ball._class.__index.initProxy = function: 0x15c47300
ball._class.__index.hasBehavior = function: 0x15c47320
ball._class.__index.addBehavior = function: 0x15c51440
ball._class.__index.__index = table: 0x15cd4f20
ball._class.__index.__index.removeBehavior = function: 0x15c51460
ball._class.__index.__index.initProxy = function: 0x15c47300
ball._class.__index.__index.hasBehavior = function: 0x15c47320
ball._class.__index.__index.addBehavior = function: 0x15c51440
ball._class.__index.__index.__index = table: 0x15cd4f20
ball._class.__index.__index.__index.removeBehavior = function: 0x15c51460
ball._class.__index.__index.__index.initProxy = function: 0x15c47300
ball._class.__index.__index.__index.hasBehavior = function: 0x15c47320
ball._class.__index.__index.__index.addBehavior = function: 0x15c51440
ball._class.__index.__index.__index.__index = table: 0x15cd4f20
ball._class.__index.__index.__index.__index.removeBehavior = function: 0x15c51460
ball._class.__index.__index.__index.__index.initProxy = function: 0x15c47300
ball._class.__index.__index.__index.__index.hasBehavior = function: 0x15c47320
ball._class.__index.__index.__index.__index.addBehavior = function: 0x15c51440
ball._class.__index.__index.__index.__index.__index = table: 0x15cd4f20
Eric [import]uid: 128346 topic_id: 23378 reply_id: 94812[/import]

I think you can see there why internal references are not to be scanned by client (our) code, though I do appreciate your problems in trying to serialize what would appear to be standard properties, such as ‘.x’ and ‘.y’, as I’ve tried to do that recently myself and realised it’s simply not possible.

Typically, for values starting with ‘_’ you want to avoid those and a really advanced debug function would keep a list of tables it’s seen and not iterate them if it encounters them again.

That doesn’t address the issue of serializing documented properties which don’t show up, of course, for which I don’t have a solution. They will show up once you set them yourself though and it is reassuring to know that those properties which don’t show up are only in the API documentation…

If you were to create a routine which iterates over a table created by someone else, it would be able to see every value they’ve provided. [import]uid: 8271 topic_id: 23378 reply_id: 94820[/import]

Thanks for shedding some light on this.

Now that I know that it can’t be done I won’t wonder and try to peek under the hood to see what can’t be seen. And it’s apparently an instance of a naive newbie question leading into programming deep waters.

I have to be careful about being too curious such that I waste time on academic questions when I need to focus on engineering my little app!

Seems that this fellow tried to muck around with object’s tables too:
http://developer.anscamobile.com/forum/2011/08/06/q-ansca-about-remove-vs-removeself

But it sounds like he know what he’s doing, whereas I don’t. :slight_smile:

Thanks,
Eric

[import]uid: 128346 topic_id: 23378 reply_id: 94943[/import]