Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AsObjectArg<T> is now implemented for &mut Gd<T> #847

Merged
merged 1 commit into from
Aug 10, 2024

Conversation

Bromeon
Copy link
Member

@Bromeon Bromeon commented Aug 8, 2024

Based on #846.

If you have a &mut Gd, you can now pass it to engine APIs, just like &Gd.

@Bromeon Bromeon added quality-of-life No new functionality, but improves ergonomics/internals c: engine Godot classes (nodes, resources, ...) labels Aug 8, 2024
@Bromeon Bromeon enabled auto-merge August 8, 2024 21:59
@Bromeon Bromeon added this pull request to the merge queue Aug 8, 2024
github-merge-queue bot pushed a commit that referenced this pull request Aug 8, 2024
`AsObjectArg<T>` is now implemented for `&mut Gd<T>`
@GodotRust
Copy link

API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-847

@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Aug 8, 2024
@Bromeon Bromeon added this pull request to the merge queue Aug 10, 2024
Merged via the queue into master with commit 712e166 Aug 10, 2024
14 checks passed
@Bromeon Bromeon deleted the qol/object-arg-mut-refs branch August 10, 2024 15:48
@Bromeon
Copy link
Member Author

Bromeon commented Nov 9, 2024

Note that there's a problem with this:

fn exchange_semester(child: &mut Gd<Node>) {
    let mut parent: Gd<Node> = child.get_parent().unwrap();
    parent.remove_child(child);
    // child enjoys time abroad
    parent.add_child(child);
}
&mut T does not implement Copy, so the first child argument (of type &mut Gd) moves out, and the second occurrence is no longer valid.
error[E0382]: use of moved value: `child`
    |
    | fn exchange_semester(child: &mut Gd<Node>) {
    |                      ----- move occurs because `child` has type `&mut godot_core::obj::Gd<godot_core::classes::Node>`, which does not implement the `Copy` trait
    |     let mut parent = child.get_parent().unwrap();
    |     parent.remove_child(child);
    |                         ----- value moved here
    |     // child enjoys time abroad
    |     parent.add_child(child);
    |                      ^^^^^ value used here after move

The solution is simple, borrow as &T instead of &mut T, with &*:

fn exchange_semester(child: &mut Gd<Node>) {
    let mut parent: Gd<Node> = child.get_parent().unwrap();
    parent.remove_child(&*child);
    // child enjoys time abroad
    parent.add_child(child);
}

Other things like the recent AsArg addition are not implemented for &mut T exclusive references and T values, to encourage properly borrowing (and discourage premature clones). I wonder if this something to consider here too -- it would mean extra &* in some places.

So, in the cases where someone has a &mut Gd, they already need to use the &* pattern as soon as the value is passed to more than one function. Maybe it's better to make this explicit from the start than have different call syntaxes? A similar argument can be made for values and borrows 🤔

@Bromeon
Copy link
Member Author

Bromeon commented Nov 9, 2024

Reverted for now in #947; I'd like to have a more solid design before we support once-consumable &mut arguments in isolated places. It doesn't only affect Gd<T> but also GString, Variant etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: engine Godot classes (nodes, resources, ...) quality-of-life No new functionality, but improves ergonomics/internals
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants