-
-
Notifications
You must be signed in to change notification settings - Fork 224
Document DynGd<_, D>
type inference.
#1142
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
Document DynGd<_, D>
type inference.
#1142
Conversation
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1142 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Apart from the : 'static
bound users need to add, are there any other ergonomic downsides of this change?
: 'static
is arguably a bit annoying since that is very unusual for most traits, but I guess if it makes inference clearer, that's probably worth it 🤔
godot-core/src/obj/dyn_gd.rs
Outdated
/// // Type can't be inferred. | ||
/// // Would result in confusing compilation error | ||
/// // since compiler would try to enforce 'static **lifetime** on our reference. | ||
/// // let mut dyn_gd = Monster::new_gd().into_dyn(); | ||
/// // no_inference(&mut *dyn_gd.dyn_bind_mut()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a separate block with compile_fail
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, instead of **lifetime**
, you could write *lifetime* (&'static mut ...)
.
godot-core/src/obj/dyn_gd.rs
Outdated
/// fn deal_damage(h: &mut dyn Health) { /* ... */ } | ||
/// | ||
/// fn no_inference(i: &mut dyn NoInference) { /* ... */ } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// fn deal_damage(h: &mut dyn Health) { /* ... */ } | |
/// | |
/// fn no_inference(i: &mut dyn NoInference) { /* ... */ } | |
/// // Two example functions accepting trait object, to check type inference. | |
/// fn deal_damage(h: &mut dyn Health) { /* ... */ } | |
/// fn no_inference(i: &mut dyn NoInference) { /* ... */ } |
godot-core/src/obj/dyn_gd.rs
Outdated
/// If class implements more than one `#[godot_dyn]` trait, type inference only works when the trait we dereference to explicitly declares | ||
/// `'static` as its supertrait. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// If class implements more than one `#[godot_dyn]` trait, type inference only works when the trait we dereference to explicitly declares | |
/// `'static` as its supertrait. | |
/// If a class implements more than one `AsDyn` relation (usually via `#[godot_dyn]`), type inference will only work when the trait | |
/// used for `D` explicitly declares a `: 'static` bound. |
godot-core/src/obj/dyn_gd.rs
Outdated
/// | ||
/// If class implements more than one `#[godot_dyn]` trait, type inference only works when the trait we dereference to explicitly declares | ||
/// `'static` as its supertrait. | ||
/// Otherwise, if only one `#[godot_dyn]` trait is implemented for a given class, the type can be properly inferred. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Otherwise, if only one `#[godot_dyn]` trait is implemented for a given class, the type can be properly inferred. | |
/// Otherwise, if only one `impl AsDyn` is present for a given class, the type can always be inferred. |
86bd36a
to
a098d0a
Compare
Personally I haven't found any downsides 🤔. I'll try to make another deep dive in a month or two to figure out what is going on – but for now, especially for I also updated comment related to #1145 (I was too focused to make it work ASAP to take care of such details 😅). |
a098d0a
to
901e79a
Compare
// Type can be inferred because `Health` explicitly declares | ||
// 'static as its supertrait. | ||
let mut obj = original_obj.clone().into_dyn(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Type can be inferred because `Health` explicitly declares | |
// 'static as its supertrait. | |
let mut obj = original_obj.clone().into_dyn(); | |
// Type can be inferred because `Health` explicitly declares a 'static bound. | |
let mut obj = original_obj.clone().into_dyn(); |
Line width 140-150 (see code style)
Also, 'static
isn't a trait, so it's not a supertrait either.
/// # Type inference | ||
/// | ||
/// If a class implements more than one `AsDyn<D>` relation (usually via `#[godot_dyn]`), type inference will only work when the trait | ||
/// used for `D` explicitly declares a `: 'static` bound. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section could probably come last, no?
Exporting is definitely more important (arguably also more than dyn-re-enrichment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I think you are right – albeit I'm finding Polymorphic dyn
re-enrichment a bit more important 🤔 (reasoning – the first two sections explain how to use it and how it works, while following ones focus on documenting various quirks)
I put Type inference
as the last section
godot-core/src/obj/dyn_gd.rs
Outdated
/// fn deal_damage(h: &mut dyn Health) { /* ... */ } | ||
/// fn no_inference(i: &mut dyn NoInference) { /* ... */ } | ||
/// | ||
/// // Type can be inferred since `static supertrait is explicitly declared for Health trait. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// // Type can be inferred since `static supertrait is explicitly declared for Health trait. | |
/// // Type can be inferred since 'static bound is explicitly declared for Health trait. |
No backtick, but apostrophe -- and no supertrait
@@ -428,7 +451,8 @@ fn dyn_gd_multiple_traits() { | |||
// ---------------------------------------------------------------------------------------------------------------------------------------------- | |||
// Example symbols | |||
|
|||
trait Health { | |||
// 'static supertrait must be explicitly declared to make type inference work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 'static supertrait must be explicitly declared to make type inference work. | |
// 'static bound must be explicitly declared to make type inference work. |
|
||
// Not recommended – for presentational purposes only. | ||
// Works because 'static bound on type is enforced in function signature. | ||
// i.e. This wouldn't work with fn get_instance_id(...). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// i.e. This wouldn't work with fn get_instance_id(...). | |
// I.e. this wouldn't work with fn get_instance_id(...). |
godot-core/src/registry/callbacks.rs
Outdated
/// # Safety | ||
/// | ||
/// - `r_is_valid` must be assignable. | ||
/// - `r_is_valid` comes uninitialized and must be set. | ||
pub unsafe extern "C" fn to_string<T: cap::GodotToString>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Safety sections are the requirements a caller must fulfill, not the requirements on the function implementation (2nd bullet point).
But let's remove it altogether, as only Godot calls it and none of the other callbacks has it. You can still mention the fact that
is_valid
comes uninitialized and must be set by this function
as a regular (non-safety) comment.
godot-core/src/registry/callbacks.rs
Outdated
pub unsafe extern "C" fn to_string<T: cap::GodotToString>( | ||
instance: sys::GDExtensionClassInstancePtr, | ||
is_valid: *mut sys::GDExtensionBool, | ||
r_is_valid: *mut sys::GDExtensionBool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert the rename. While it follows Godot convention, it's inconsistent with all the other callback signatures here. It's even inconsistent with the other parameter in this exact function (would be p_instance
in Godot).
- Document when type inference works and when it doesn't. - Explicitly enforce `Trait: 'static` for `DynGd<T, D>` and `AsDyn<D>` – mostly for clarity, creating non-static `DynGd<T, D>` was already pretty much impossible, and `T` – GodotClass – must be 'static either way.
901e79a
to
3529708
Compare
Closes: #1026
Trait: 'static
forDynGd<T, Trait>
andAsDyn<Trait>
(we have no means to track lifetimes of given object either way which means it might be invalidated at any point – albeit creating suchDynGd
is hard, sinceGodotClass
must be'static
either way).Despite messing with it for some time I couldn't force compiler to properly infer given types – thus I limited myself to merely documenting it 😒.