Is my way of running a method in another thread, the most efficient?

I need to run a method of a table in a separate moduleScript, in another thread. I used coroutine for this.

The problem was that coroutine.wrap() expects the function to be sent as an argument. I thought that I could use coroutine.wrap(object:method()), but it instead runs the method. I tried using coroutine.wrap(object:method), but that just throws an exception.

So, I had to use coroutine.wrap(object.method), but that does not send the object to the method as an argument as object:method() does.

To solve this problem, I typed:

tempMethod = coroutine.wrap(object.method)
tempMethod(object)

I sent the object manually to the method. It works, but, I am worried that it may not be the best way to solve this.

Your method is the proper way to send an argument to a function wrapped in a coroutine, including functions. It’s the same as the following, just without the variable:

coroutine.wrap(function(variable)
    print(variable) --> Hello!
end)('Hello!') -- this bracket says to call the function and pass the string 'Hello!' as the argument.

You could also do the following as the variable is within the scope of the coroutine, not sure which is more expensive if any though:

local variable = 'Hello!'
local cor = coroutine.wrap(function()
    print(variable) --> Hello!
end)
cor()

Since you’re passing a function object, it will work.

local funcs = {}

function funcs.Function()
    print('Hello!')
end

Then when creating the coroutine:

coroutine.wrap(funcs.Function)(--[[you can pass any arguments to the function here]]) -- prints Hello!

For passing arguments to that function,

local funcs = {}

function funcs.Function(arg)
    print(arg)
end

…

coroutine.wrap(funcs.Function)('Hello!')

If I initialise “self.variable” within the method, would it be considered a bad practice to send the object manually? If object:method() worked, I wouldn’t have sent the object manually, because it would have been done automatically.

local funcs = {}

function funcs.Function()
    self.variable = 0
    print(self.variable)
end
…

coroutine.wrap(funcs.Function)(object) --the method will use object as self

Ohhh, I think I get what you mean.

That won’t work as the first argument inside of funcs.Function has to be self (which is the function environment IIRC).

Using a colon for calling a function is called syntactical sugar.

So let’s use game:GetService(‘Workspace’) for example.

If we do game.GetService('Workspace'), it doesn’t work. It will return an error similar to “Expected . instead of :”

You are in fact able to bypass this by sending the function environment to the function (which in our case would be game).

game.GetService(game, 'Workspace') -- this works! We are sending what would be considered 'self' to the function.

So in our case, we would have to send the funcs table as the first argument to the function

local funcs = {}

function funcs.Function(self, arg)
    print(arg)
    self.variable = 'ok'
    for i,v in pairs(self) do
        print(i,v)
    end
end

coroutine.wrap(funcs.Function)(funcs, 'Hello!') 
--[[Output:
Hello! -- this is what is being printed. It is what was passed as the `arg` argument.
Function	function: 0x55d4d37c4820
variable	ok -- the variable we've assigned
]]

What this allows us to do now, is call that function with a colon.

funcs:Function('Hello!')
--[[Output:
Hello!
Function	function: 0x55d4d37c4820
variable	ok
]]

Basically a colon is telling the function that an invisible variable called self exists inside of the function without having to manually declare it.

So how is this relevant in your case?

function funcs:Function(arg)
    self.variable = 'ok'
    print(self.variable)
end

coroutine.wrap(funcs.Function(funcs, 'Hello!')) -- You are able to do this
funcs:Function('Hello!') -- AND this.

And that is how you send a function using a colon (a method) as an argument.

2 Likes

I forgot to mention that/ I didn’t notice that, in contrast with funcs.Function, my function was actually declared with a colon.

As far as I understand, you agree that it’s the proper way to pass the object as self in coroutine.wrap().

Thank you for replying so fast. I expected to get a reply tomorrow.

Yeah exactly. That would be the (and only I think) way to pass a method through a coroutine/another thread.

Basically to summarize:

object:method() is the same as object.method(object)

The only difference is that in object.method(object), you’re manually inputting the function environment whereas with object:method(), it basically knows its own function environment.