Page 1 of 1

How to determine if a value is a LÖVE object?

Posted: Thu Mar 06, 2025 9:26 pm
by chimmihc
I am creating an API with editable properties and would like to have basic type checking in it.

For regular Lua values this is simple enough but I can't find a way to check if a value is a LÖVE object.

I thought to extract Object:typeOf for this but calling it with non LÖVE objects actually causes the process to crash silently.

Re: How to determine if a value is a LÖVE object?

Posted: Thu Mar 06, 2025 9:44 pm
by dusoft
https://www.lua.org/pil/2.html

Usually: "userdata" for LÖVE.

Also:
https://love2d.org/wiki/Types
for detailed type.

Re: How to determine if a value is a LÖVE object?

Posted: Fri Mar 07, 2025 3:25 pm
by qwdqwqwffqw
If the result of type(value) is 'userdata', then using tostring() might help? - You can check first part of returned string, probably without crashing.

Or, maybe you can use getmetatable() and compare it with metatables of love Objects.

Code: Select all

local loveTypes = {
	[getmetatable(love.graphics.newImage('img.png'))] = true,
	... -- [metatable of love Object] = true
}

function isLove(v)
	return loveTypes[getmetatable(v)]
end

Re: How to determine if a value is a LÖVE object?

Posted: Fri Mar 07, 2025 7:07 pm
by chimmihc
After a bit of testing it does seem objects of a type share the same metatable so that works.

Re: How to determine if a value is a LÖVE object?

Posted: Sat Mar 08, 2025 7:18 am
by zorg
chimmihc wrote: Thu Mar 06, 2025 9:26 pm I am creating an API with editable properties and would like to have basic type checking in it.
For regular Lua values this is simple enough but I can't find a way to check if a value is a LÖVE object.
I thought to extract Object:typeOf for this but calling it with non LÖVE objects actually causes the process to crash silently.

Code: Select all

function isLoveObjectType(x, t)
    assert(type(t) = 'string', "Second parameter needs to be a string that's a valid Löve Type.")
    local t = t or 'Object' -- If no specific type is given, default to Object.
    if not x then return false end
    if not type(x) == 'userdata' then return false end
    if not x.typeOf then return false end
    if not type(x.typeOf) == 'function' then return false end
    return x:typeOf(t)
end
This might be the safest implementation, uses typeOf, and can be used to test for specific subtypes as well. :3

Re: How to determine if a value is a LÖVE object?

Posted: Sat Mar 08, 2025 10:34 am
by pgimeno
I was thinking something not too different from what zorg has posted. zorg's code has some bugs and some redundancy, though.

- The first two lines should be swapped, otherwise you would always need to pass a string as the second parameter and the second line would be redundant.
- The line `if not x then return false end` is redundant: the next line will return type `nil` and bail out.
- The line `if not x.typeOf then return false end` is redundant for the same reason.
- `not a == b` negates a, not the result of the comparison. Instead of adding `not`, the `==` can be replaced with `~=`.
- I'm not sure if any userdata object can be accessed like a table even if it doesn't have a metatable, but ISTR that it can't, meaning that code would crash in that case.

This was my approach:

Code: Select all

local function isLoveObject(obj)
  if type(obj) == "userdata" then
    local mt = debug.getmetatable(obj)
    if type(mt) == "table" then
      for k, v in pairs(debug.getregistry()) do
        if v == mt and type(v.type) == "function" then
          return true  -- or you could return obj:type() instead to know the exact type
        end
      end
    end
  end
  return false
end
It's not very fast though, because of the loop, and it breaks compilation due to the use of pairs().