Types: color vs. vec4 vs vec3 vs vec2

I am eying to write a generic load/save routine for arbitrary type data. I have in the same class a color, a vec4, a vec3 and a vec2 variable. I am Abe to persist them with JSON.

When I reconstruct these objects, I need to determine the type the variable came from. I’ve already thought about hacking the persistence with tags to reconstruct, but I still need to figure out what my class definition type is that I came from.

How can I programmatically get color vs vec4, for example? They are all classified as userdata. Another example question: Does userdata have a property to determine what is a vec4 vs a vec3?

Whoa, interesting!

So…if you stick ANYTHING into a color, it will downgrade into the appropriate vec type!

Hi @aciolino, You mean color(gray), color(gray, a), color(r, g, b) and color(r, g, b, a) ?

Different - if you have a value at (255,128,64,255), what is that? It’s a vec4 or it’s a color object.

What I find is that if you assign this to a vec2, you’ll get (255,128) so a userdata can be used for a color or a point.

Hello @aciolino. Some time ago i posted a big mesh saving utility. There is a convert() class in it, and in the convert class i have this function that returns the type of userdata. You can see the trick i have used below:

-- type(v):"nil", "number", "string", "boolean", "table", "function", "thread", "userdata".
function Convert:type(x)
    local txt = type(x)
    function typeCompare(x,ref)
    -- nb: returns an error if x or ref have no metatable!
    local i = getmetatable(x).__index
    local j = getmetatable(ref).__index
    return (i==j)
    end
    if txt == "userdata" then
        if     typeCompare(x,vec2())     then txt ="vec2" 
        elseif typeCompare(x,vec3())     then txt ="vec3" 
        elseif typeCompare(x,color())    then txt ="color" 
        elseif typeCompare(x,image(1,1)) then txt ="image" 
        elseif typeCompare(x,matrix())   then txt ="matrix" 
        elseif typeCompare(x,mesh())     then txt ="mesh" 
        end
    end
    if txt == "table" then
        txt = "{"..self:type(x[1]).."}"
    end
    return txt
end

.@Jmv38 Quick style question for you. Why are you defining typeCompare every time the function Convert:type is called? Wouldn’t it make more sense to define it once outside this function and then call it from within? In fact, wouldn’t the following be a little more compact:

function Convert:type(x)
    local txt = type(x)
    local i = getmetatable(x).__index
    local j = getmetatable(ref).__index
    return (i==j)
    end
    if txt == "userdata" then
        local mt = getmetatable(x).__index
        if       mt == getmetatable(vec2()).__index    then txt ="vec2" 
        elseif mt == getmetatable(vec3()).__index    then txt ="vec3" 
        elseif mt == getmetatable(color()).__index     then txt ="color" 
        elseif mt == getmetatable(image()).__index    then txt ="image" 
        elseif mt == getmetatable(matrix()).__index   then txt ="matrix" 
        elseif mt == getmetatable(mesh()).__index     then txt ="mesh" 
        end
    elseif txt == "table" then
        txt = "{"..self:type(x[1]).."}"
    end
    return txt
end

But isn’t this more compact :wink: (and ref is undefined?)


local typeTable = {
    [getmetatable(vec2()).__index  ] = "vec2", 
    [getmetatable(vec3()).__index  ] = "vec3",
    [getmetatable(color()).__index ] = "color", 
    [getmetatable(image(1,1)).__index ] = "image", 
    [getmetatable(matrix()).__index] = "matrix", 
    [getmetatable(mesh()).__index  ] = "mesh" 
}
function convertType(x)
    local txt = type(x)
    if txt == "userdata" then
        return typeTable[getmetatable(x).__index]
    elseif txt == "table" then
        return "{"..convertType(x[1]).."}"
    end
    return txt
end

@Andrew_Stacey I think you forgot to remove the following


    local i = getmetatable(x).__index
    local j = getmetatable(ref).__index
    return (i==j)
    end

Also, image seems to be a function and requires two arguments?

.@Xavier Whoops! Yes, I just edited it without testing it.

.@tnlogy Looks better, yes.

It’s certainly better form than me ‘forcing’ it the way I am. That said, it’s working either way, which was quite a surprise to me. I do like the code by @tnlogy.

Thanks all for the quick repsonse!

Hello @andrew_Stacey and @tnlogy.
Function in function: it is just a way to hide the local function from the rest, there Are already too many visible function in my code.
If i look at both your code: metatable and __index appear at many locations. i am not familiar with these keywords, so they scared me. Then i used them only once, in an encapsulated location: this might not be the fastest code (but i dont need speed here) nor the most compact (but i favor debuggability against compactness). And it did the job for me, when i needed to… I always favor readability (according to my -low- level of programming skills) against optimization, except when speed is a key factor… Voilà.