Skip to main content
added 526 characters in body
Source Link
Theraot
  • 28.3k
  • 4
  • 55
  • 83

The types Callable, String and StringName for that matter, are all value types. Anywhere you pass them, you are passing a copy. StringName is an internal string.

So when you pass the name of the method to create the Callable, the Callable has a copy. And when you pass the Callable to connect the signals, that is a copy.

To reiterate, they are not references. So changing the string that has the name of the method you passed to the Callable has nothing to do with the Callable, nor the signal connection.

In fact, Callable, and StringName are immutable. String can be manipulated, but we rarely do that. So no, you cannot change the method that the Callable points to.


By the way, this code:

c = Callable(self, method)
flipTimer.connect("timeout", c)

Is equivalent to this:

c = Callable(self, method)
flipTimer.timeout.connect(c)

You don't need to use a String to reference signals anymore.


Now, since Callable are value types, any local Callable is freed when it goes out of scope. So they work very well for short lived values.

Thus, you don't need to use expression.execute to call a method by name, you can do this:

Callable(obj, method_name).call()

In fact, you don't need a Callable for this, since Object has a call method:

obj.call(method_name)

Which - by the way - was valid in Godot 3.


Anyway, you have two one shot Timers. Instead of trying to combine them into one one shot Timer, I suggest you use the SceneTreeTimers:

var c := Callable(obj, "actual_method")
get_tree().create_timer(timeout_seconds).timeout.connect(c)

In fact, since you would know which one shot Timer you are supposed to call, you can connect the method directly:

get_tree().create_timer(timeout_seconds).timeout.connect(obj.actual_method)

Notice that I'm not adding () after the method name, and thus I'm not calling it. That is obj.actual_method() calls the method, obj.actual_method references the method (the equivalent of making a Callable).

Godot will free the SceneTreeTimer once they emit their timeout signal.

Not not free your SceneTreeTimer manually, otherwise others timers will start behaving incorrectly due to Godot still referencing invalid memory (where a timer created afterwards could be allocated into).


You might also be interested in anonymous inline methods ("lambda functions"). For example:

get_tree().create_timer(timeout_seconds).timeout.connect(
    func():
        prints("hello world")
)

It could also be all in a single line.

The lambda function is also a Callable.

The types Callable, String and StringName for that matter, are all value types. Anywhere you pass them, you are passing a copy. StringName is an internal string.

So when you pass the name of the method to create the Callable, the Callable has a copy. And when you pass the Callable to connect the signals, that is a copy.

To reiterate, they are not references. So changing the string that has the name of the method you passed to the Callable has nothing to do with the Callable, nor the signal connection.

In fact, Callable, and StringName are immutable. String can be manipulated, but we rarely do that. So no, you cannot change the method that the Callable points to.


By the way, this code:

c = Callable(self, method)
flipTimer.connect("timeout", c)

Is equivalent to this:

c = Callable(self, method)
flipTimer.timeout.connect(c)

You don't need to use a String to reference signals anymore.


Now, since Callable are value types, any local Callable is freed when it goes out of scope. So they work very well for short lived values.

Thus, you don't need to use expression.execute to call a method by name, you can do this:

Callable(obj, method_name).call()

In fact, you don't need a Callable for this, since Object has a call method:

obj.call(method_name)

Which - by the way - was valid in Godot 3.


Anyway, you have two one shot Timers. Instead of trying to combine them into one one shot Timer, I suggest you use the SceneTreeTimers:

var c := Callable(obj, "actual_method")
get_tree().create_timer(timeout_seconds).timeout.connect(c)

In fact, since you would know which one shot Timer you are supposed to call, you can connect the method directly:

get_tree().create_timer(timeout_seconds).timeout.connect(obj.actual_method)

Godot will free the SceneTreeTimer once they emit their timeout signal.

Not not free your SceneTreeTimer manually, otherwise others timers will start behaving incorrectly due to Godot still referencing invalid memory (where a timer created afterwards could be allocated into).

The types Callable, String and StringName for that matter, are all value types. Anywhere you pass them, you are passing a copy. StringName is an internal string.

So when you pass the name of the method to create the Callable, the Callable has a copy. And when you pass the Callable to connect the signals, that is a copy.

To reiterate, they are not references. So changing the string that has the name of the method you passed to the Callable has nothing to do with the Callable, nor the signal connection.

In fact, Callable, and StringName are immutable. String can be manipulated, but we rarely do that. So no, you cannot change the method that the Callable points to.


By the way, this code:

c = Callable(self, method)
flipTimer.connect("timeout", c)

Is equivalent to this:

c = Callable(self, method)
flipTimer.timeout.connect(c)

You don't need to use a String to reference signals anymore.


Now, since Callable are value types, any local Callable is freed when it goes out of scope. So they work very well for short lived values.

Thus, you don't need to use expression.execute to call a method by name, you can do this:

Callable(obj, method_name).call()

In fact, you don't need a Callable for this, since Object has a call method:

obj.call(method_name)

Which - by the way - was valid in Godot 3.


Anyway, you have two one shot Timers. Instead of trying to combine them into one one shot Timer, I suggest you use the SceneTreeTimers:

var c := Callable(obj, "actual_method")
get_tree().create_timer(timeout_seconds).timeout.connect(c)

In fact, since you would know which one shot Timer you are supposed to call, you can connect the method directly:

get_tree().create_timer(timeout_seconds).timeout.connect(obj.actual_method)

Notice that I'm not adding () after the method name, and thus I'm not calling it. That is obj.actual_method() calls the method, obj.actual_method references the method (the equivalent of making a Callable).

Godot will free the SceneTreeTimer once they emit their timeout signal.

Not not free your SceneTreeTimer manually, otherwise others timers will start behaving incorrectly due to Godot still referencing invalid memory (where a timer created afterwards could be allocated into).


You might also be interested in anonymous inline methods ("lambda functions"). For example:

get_tree().create_timer(timeout_seconds).timeout.connect(
    func():
        prints("hello world")
)

It could also be all in a single line.

The lambda function is also a Callable.

Source Link
Theraot
  • 28.3k
  • 4
  • 55
  • 83

The types Callable, String and StringName for that matter, are all value types. Anywhere you pass them, you are passing a copy. StringName is an internal string.

So when you pass the name of the method to create the Callable, the Callable has a copy. And when you pass the Callable to connect the signals, that is a copy.

To reiterate, they are not references. So changing the string that has the name of the method you passed to the Callable has nothing to do with the Callable, nor the signal connection.

In fact, Callable, and StringName are immutable. String can be manipulated, but we rarely do that. So no, you cannot change the method that the Callable points to.


By the way, this code:

c = Callable(self, method)
flipTimer.connect("timeout", c)

Is equivalent to this:

c = Callable(self, method)
flipTimer.timeout.connect(c)

You don't need to use a String to reference signals anymore.


Now, since Callable are value types, any local Callable is freed when it goes out of scope. So they work very well for short lived values.

Thus, you don't need to use expression.execute to call a method by name, you can do this:

Callable(obj, method_name).call()

In fact, you don't need a Callable for this, since Object has a call method:

obj.call(method_name)

Which - by the way - was valid in Godot 3.


Anyway, you have two one shot Timers. Instead of trying to combine them into one one shot Timer, I suggest you use the SceneTreeTimers:

var c := Callable(obj, "actual_method")
get_tree().create_timer(timeout_seconds).timeout.connect(c)

In fact, since you would know which one shot Timer you are supposed to call, you can connect the method directly:

get_tree().create_timer(timeout_seconds).timeout.connect(obj.actual_method)

Godot will free the SceneTreeTimer once they emit their timeout signal.

Not not free your SceneTreeTimer manually, otherwise others timers will start behaving incorrectly due to Godot still referencing invalid memory (where a timer created afterwards could be allocated into).