Skip to content

Commit edbd10f

Browse files
authored
Added faq entry on runtime polymorphism (#55)
* added faq entry on runtime polymorphism * improvements from review Co-authored-by: bluenote10 <bluenote10@users.noreply.github.com>
1 parent cf23769 commit edbd10f

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

src/faq/code.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,36 @@ Note: As `TRef<T>` is a temporary pointer, it will be necessary to get the base
325325
This can be done with the [`TRef<T>::claim()`](https://docs.rs/gdnative/latest/gdnative/struct.TRef.html#method.claim) function that will return the persistent version of the pointer that you can store in your class.
326326

327327

328+
## How do I implement function arguments that accept any Godot subclass (runtime polymorphism)?
329+
330+
This can be achieved by a combination of `SubClass` and `upcast`.
331+
332+
For example, let's assume we want to implement a helper function that should accept any kind of [`Container`](https://docs.godotengine.org/en/stable/classes/class_control.html#class-control). The helper function can make use of `SubClass` and `upcast` as follows:
333+
334+
```rust
335+
fn do_something_with_container<T>(container: TRef<'_, T>)
336+
where T: GodotObject + SubClass<Container>
337+
{
338+
// First upcast to a true container:
339+
let container = container.upcast::<Container>();
340+
// Now you can call `Container` specific methods like:
341+
container.set_size(...);
342+
}
343+
```
344+
345+
This function can now be used with arbitrary subclasses, for instance:
346+
347+
```rust
348+
fn some_usage() {
349+
let panel_container: Ref<PanelContainer> = PanelContainer::new().into_shared();
350+
let panel_container: TRef<PanelContainer> = unsafe { panel_container.assume_safe() };
351+
do_something_with_container(panel_container);
352+
}
353+
```
354+
355+
Note that `SubClass` is only a marker trait that models the inheritance relationship of Godot classes, and doesn't perform any conversion by itself. For instance, `x: Ref<T>` or `x: TRef<'_, T>` satisfying `T: GodotObject + SubClass<Container>` doesn't mean that `x` can be used as a `Container` directly. Rather, it ensures that e.g. `x.upcast::<Container>()` is guaranteed to work, because `T` is a subclass of `Container`. Therefore, it is a common pattern to use `SubClass` constraints in combination with `.upcast()` to convert to the base class, and actually use `x` as such.
356+
357+
328358
## What is the Rust equivalent to `onready var` in GDScript
329359

330360
Rust does not have a direct equivalent to `onready var`. The most idiomatic workaround with Rust is to use `Option<Ref<T>>` of you need the Godot node type or `Option<Instance<T>>` if you are using a Rust based `NativeClass`.

0 commit comments

Comments
 (0)