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

Deciding between &T and TRef<T> #56

Open
bluenote10 opened this issue Nov 13, 2021 · 4 comments
Open

Deciding between &T and TRef<T> #56

bluenote10 opened this issue Nov 13, 2021 · 4 comments
Labels
new-topic A new topic to be added has been requested

Comments

@bluenote10
Copy link
Contributor

In general godot-rust allows to use e.g. either owner: &Node or owner: TRef<Node> on exported methods, as noted in the Class registration section:

The parameter can be a shared reference &T or a TRef.

Unless I have missed something, the book doesn't go into details why one would chose one over the other. In practice this means that most developers go for &T because it's simpler. This is probably the reason why many people run into problems when trying to set up signals, in particular because this example suggest that passing owner should just work. Searching the discord history shows many cases of failed attempts to get signal connection to work, because owner.connect takes a target: AsArg which only works with owner: TRef<T> but not with owner: &T (unless falling back to unsafe { owner.assume_shared() }). I'm not sure if this limitation is by design or can perhaps be avoided eventually (c.f. godot-rust/gdnative#749). So far this is the only difference I'm aware of, but there may be further differences. Regarding the book I'd suggest:

  • In case one form is a strict superset of the other, the book should probably recommend using only the more powerful one. I.e, if the AsArg limitation is the only difference, it would make sense to recommend using TRef<T> because it can do strictly more than &T.
  • If there are things that can only be done by one form, but not by the other and vice versa, it would be nice to list these pros/cons of both forms to help with the decision.
@bluenote10 bluenote10 added the new-topic A new topic to be added has been requested label Nov 13, 2021
@jacobsky
Copy link
Contributor

Thanks for input! I think there's merit to adding information in the Ref, TRef, and Instance section of the book.

Would you like to take point on a PR for mentioning this?

@bluenote10
Copy link
Contributor Author

Would you like to take point on a PR for mentioning this?

If you mean if I could contribute anything: I guess I'm still struggling too much with some fundamental questions like:

  1. Is AsArg the only real difference between &T and TRef<T>?
  2. Are there other practical use cases despite setting up signals that require AsArg?
  3. Since AsArg seems limiting, why is it needed at all, and could &T support it as well?

Especially the latter needs to be checked first from the bindings perspective. CC @Bromeon


As as side note, answering (2) is often a bit tricky, presumably due to the auto-generated nature of the bindings. For instance when searching the docs for AsArg it shows zero usages "In Parameters" and "In Return Types", making it hard to understand its purpose from its usage:

image

@Bromeon
Copy link
Member

Bromeon commented Nov 15, 2021

Is AsArg the only real difference between &T and TRef<T>?

In practice, it's mostly that and claim(), the ability to turn the TRef into a Ref, i.e. a persistent reference you can store for later use.

You can imagine a TRef<T> as a bare &T shared reference + some book-keeping overhead to integrate it with GDNative.


Since AsArg seems limiting, why is it needed at all, and could &T support it as well?

A lot of this functionality is part of GodotObject, which is the bound for T in TRef<T>, and not part of TRef itself.
A TRef contains no other data than &T:

pub struct TRef<'a, T: GodotObject, Own: Ownership = Shared> {
    obj: &'a T,
    _marker: PhantomData<Own>,
}

However, it contains other information, namely the generic type parameter Own. Among other things, the ownership policy determines which TRef instantiations are safe to be passed to the library (e.g. ThreadLocal ones are not).

So no, we cannot safely implement AsArg for &T at the moment.


This being said, a lot of these things are currently in the process of being re-thought, see godot-rust/gdnative#808 for example. So while we can give recommendation on when to use TRef<T> and when to use &T, this may become obsolete.

Generally, with TRef<T> you're on the safe side, as you can always use the Deref impl to turn it into a &T. There's no real reason to use &T except for simplicity/ergonomics.

@bluenote10
Copy link
Contributor Author

Thanks for the clarifications! In this case it might be best to wait a bit and see how things evolve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new-topic A new topic to be added has been requested
Projects
None yet
Development

No branches or pull requests

3 participants