Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knowing if a value can be called

Tags:

lua

Note that this question is about pure Lua. I do not have access to any module or the C side. Additionally, I can not use the IO, the OS or the debug library.

What I'm trying to make is a function that receives, as parameters:

  • a number that is an ammount of second
  • a callable value

By 'a callable value', I mean a value that can be called. This can be:

  • a function
  • a table with a metatable that allows calling (through a __call metamethod)

Here's an example of a callable table:

local t = {}
setmetatable(t, {
  __call = function() print("Hi.") end
})
print(type(t)) --> table
t() --> Hi.

Here's the function:

function delay(seconds, func)
  -- The second parameter is called 'func', but it can be anything that is callable.
  coroutine.wrap(function()
    wait(seconds) -- This function is defined elsewhere. It waits the ammount of time, in seconds, that it is told to.
    func() -- Calls the function/table.
  end)()
end

But I have a problem. I want the function to throw an error if the parameter 'func' is not callable.

I can check if it is a function. But what if it is a table with a metatable that allows calling? If the metatable of the table is not protected by a __metatable field, then, I can check the metatable to know if it is callable, but, otherwise, how would I do it?

Note that I have also thought about trying to call the 'func' parameter with pcall, to check if it is callable, but to do that, I need to call it prematurely.

Basically, here's the problem: I need to know if a function/table is callable, but without trying to call it.

like image 411
Mark Avatar asked Sep 26 '11 03:09

Mark


People also ask

What is the difference between precision and uncertainty?

The degree of accuracy and precision of a measuring system are related to the uncertainty in the measurements. Uncertainty is a quantitative measure of how much your measured values deviate from a standard or expected value.

What is uncertainty and error?

The main difference between errors and uncertainties is that an error is the difference between the actual value and the measured value, while an uncertainty is an estimate of the range between them, representing the reliability of the measurement.

What is difference between precision and accuracy?

Accuracy and precision are alike only in the fact that they both refer to the quality of measurement, but they are very different indicators of measurement. Accuracy is the degree of closeness to true value. Precision is the degree to which an instrument or process will repeat the same value.

How do you write an IF THEN formula in Excel?

Use the IF function, one of the logical functions, to return one value if a condition is true and another value if it's false. For example: =IF(A2>B2,"Over Budget","OK") =IF(A2=B2,B4-A4,"")


2 Answers

In general, if the metatable does not want you to be able to get it (by defining __metatable to being something special), then you're not going to get it. Not from Lua.

However, if you want to cheat, you can always use debug.getmetatable, which will return the metatable associated with that object.


You don't have to prematurely call anything with pcall. Observe:

pcall(function(...) return PossibleFunction(...) end, <insert arguments here>)
like image 113
Nicol Bolas Avatar answered Oct 01 '22 03:10

Nicol Bolas


function iscallable(x)
    if type(x) == 'function' then
        return true
    elseif type(x) == 'table' then
        -- It would be elegant and quick to say
        -- `return iscallable(debug.getmetatable(x))`
        -- but that is actually not quite correct
        -- (at least in my experiments), since it appears
        -- that the `__call` metamethod must be a *function* value
        -- (and not some table that has been made callable)
        local mt = debug.getmetatable(x)
        return type(mt) == "table" and type(mt.__call) == "function"
    else
        return false
    end
end

return iscallable

Then you can do

> = iscallable(function() end)
true
> = iscallable({})
false
> = iscallable()
false
> = iscallable(nil)
false
> x = {}
> setmetatable(x, {__call=function() end})
> = iscallable(x)
true

If you don't have access to the debug library, then you may have trouble being totally accurate since you can mess with metatables. You could use pcall but its hard to separate out the errors properly. Even if you search for a particular error string as in the other answer here, that might be because of something inside the function being called not being callable, not this particular value not being callable, if that makes sense.

like image 27
theram Avatar answered Oct 01 '22 02:10

theram