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

#[base] attribute is no longer necessary #577

Merged
merged 4 commits into from
Jan 25, 2024
Merged

#[base] attribute is no longer necessary #577

merged 4 commits into from
Jan 25, 2024

Conversation

Bromeon
Copy link
Member

@Bromeon Bromeon commented Jan 22, 2024

Changes

#[derive(GodotClass)]
pub struct Hud {
    #[base]
    base: Base<RefCounted>,
}

can now be written as:

#[derive(GodotClass)]
pub struct Hud {
    base: Base<RefCounted>,
}

The rationale is to reduce clutter and repetition (#[base] base: Base<Self::Base> 😨), while still functioning in almost all cases. It also follows prior art where non-annotated items of a proc macro are inspected without being annotated:

  • OnReady<T> type inference (exactly like here)
  • struct field names for the #[class(init)] default implementation
  • detection of function presence in #[godot_api] impl I... for MyClass blocks

With the convention of using base as the field name (although this is still not required) and the necessity to use Base<T> as its type, I don't think code becomes less readable. Imo the magic budget for this change is justifiable, as there is little potential for confusion and the remaining code is valid Rust, just not wired up.

Furthermore, it is no longer possible to accidentally forget the #[base] attribute. This was previously possible as long as the field was not accessed (with only unused-code warning, which is not uncommon during gamedev prototyping).

An alternative considered was to keep #[base], but reduce repetition on the type, i.e. #[base] base: Node. The problem is that derive macros cannot modify their output, so #[derive(GodotClass)] would need to be converted into an attribute macro, which comes with its own share of implications.

Compatibility

In typical fashion for godot-rust, existing code that uses #[base] keeps working but now gets a warning.
The attribute itself becomes deprecated and will be removed in the future.

Fine-grained control

Magic inference should work in 99% of cases, but to handle the 1%, you can help the proc-macro with hints, which allow overriding the inference with explicit intent.

type Super<T> = godot::obj::Base<T>;
type Base<T> = godot::obj::Gd<T>;

#[derive(godot::register::GodotClass)]
#[class(base = Node)]
struct MyStruct {
   #[hint(base)] // will be inferred as base
   base: Super<Node>,

   #[hint(no_base)] // will NOT be inferred as base
   unbase: Base<Node>,
}

The new #[hint] attribute also supports onready and no_onready keys; something that wasn't possible to configure before.

@Bromeon Bromeon added quality-of-life No new functionality, but improves ergonomics/internals c: register Register classes, functions and other symbols to GDScript labels Jan 22, 2024
@GodotRust
Copy link

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

@0awful
Copy link
Contributor

0awful commented Jan 22, 2024

With the convention of using base as the field name (although this is still not required)

How does it work with different field names? Does the "hint" semantics handle this?

@StatisMike
Copy link
Contributor

@0awful From my understanding of the source and description I believe the name is irrevelant, only the Base<T> type is (at least currently) taken into account.

Comment on lines 295 to 299
// deprecated #[base]
if KvParser::parse(&named_field.attributes, "base")?.is_some() {
has_deprecated_base = true;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to have an explicit deprecation warning for this, why not make it work like it used to at least until we remove the deprecation warning? As is this deprecation warning doesn't help that much if your #[base] declaration is incompatible with the new way of finding base fields (like say with a type alias).

Copy link
Member Author

@Bromeon Bromeon Jan 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, most existing code will keep working due to it using Base<T> already. But it should not be too hard to make #[base] have the same semantics as #[hint(base)], I can do that. Thanks 🙂

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, also quickly tested it by replacing one of the #[hint(base)] with #[base] in integration tests.

@Bromeon Bromeon added this pull request to the merge queue Jan 25, 2024
Merged via the queue into master with commit d873d8b Jan 25, 2024
16 checks passed
@Bromeon Bromeon deleted the qol/baseless branch January 25, 2024 20:40
@Bromeon Bromeon mentioned this pull request Jul 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: register Register classes, functions and other symbols to GDScript quality-of-life No new functionality, but improves ergonomics/internals
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants