#[func(virtual)]
: override virtual Rust functions in GDScript
#606
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This adds support for godotengine/godot#87758 in Rust.
Since that PR is not yet merged, CI will fail.
Feature description
If you have a Rust method
, you can now attach a script to an instance of
MyClass
and override this method. This should work for all sorts of scripts, but most common is GDScript:Calling
self.greet()
in Rust will now directly return either"Rust"
(if no script is attached) or"GDScript"
(if a script is attached).greet()
thus always implements late-binding, you cannot call it statically. If that is desired, a separate Rust method can be declared.API Design
I deliberately chose the most lightweight syntactical option, since it's very easy to understand and use. Also, turning an existing method into a virtual one requires just adding one keyword.
A "more idiomatic" approach with traits and impls was also considered.
However, this:
virtuals=
part), i.e. also error potentialThe primary goal of gdext is to be ergonomic and useful in practice, and the
trait/impl
approach is pretty much the antithesis thereof. But I believe#[func(virtual)]
's late-binding semantics are simple enough for users to understand.Future work
A few things are not done:
Re-entrancy: we can see if this can be integrated with
base/base_mut
somehow, to allow the script to call back to the same object.#[func(gd_self)]
can be used to achieve this.Required implementation: at the moment, the user must provide a default implementation. Sometimes, you'd want to force the script to override a method though.
_ready()
that a script is attached and the corresponding function is overridden. This would move the error from the time of call to the time of scene-entering.Calling
super
methods.#[func]
.Dynamic dispatch from script side.
greet
in the above example can either call the script implementation or the Rust fallback.obj._greet()
will either call the script implementation, or fail if there is no script.#[func]
-- just like for thesuper
case. Concretely, this other#[func]
would forward the call to Rust-sidegreet
(thus dispatch dynamically), and would be accessible from GDScript.Diagnostics
Godot already provides quite a good error on signature mismatch:
Depending on user feedback, we can see if there are additional error messages/diagnostics we can provide.