Skip to content

Commit

Permalink
Remove #[base] attribute (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bromeon authored Jan 25, 2024
1 parent 8961242 commit 0ee1e6d
Show file tree
Hide file tree
Showing 7 changed files with 14 additions and 21 deletions.
8 changes: 3 additions & 5 deletions src/intro/hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ struct Player {
speed: f64,
angular_speed: f64,

#[base]
base: Base<Sprite2D>
}
```
Expand All @@ -268,12 +267,11 @@ Let's break this down.

4. We define two fields `speed` and `angular_speed` for the logic. These are regular Rust fields, no magic involved. More about their use later.

5. The `#[base]` attribute declares the `base` field, which allows `self` to access the base instance (via composition, as Rust does not have
5. The `Base<T>` type is used for the `base` field, which allows `self` to access the base instance (via composition, as Rust does not have
native inheritance). This enables two methods that can be accessed as `self.base()` and `self.base_mut()` on your type (through an extension
trait).

- The field must have type `Base<T>`.
- `T` must match the declared base class. For example, `#[class(base=Sprite2D)]` implies `Base<Sprite2D>`.
- `T` must match the declared base class. For example, `#[class(base=Sprite2D)]` implies `Base<Sprite2D>`.
- The name can be freely chosen, but `base` is a common convention.
- You do not _have to_ declare this field. If it is absent, you cannot access the base object from within `self`.
This is often not a problem, e.g. in data bundles inheriting `RefCounted`.
Expand Down Expand Up @@ -345,7 +343,7 @@ impl ISprite2D for Player {
```

GDScript uses property syntax here; Rust requires explicit method calls instead. Also, access to base class methods -- such as `rotate()`
in this example -- is done via the `#[base]` field.
in this example -- is done via `base()` and `base_mut()` methods.

```admonish warning title="Direct field access"
Do not use the `self.base` field directly. Use `self.base()` or `self.base_mut()` instead, otherwise you won't be able to access and call
Expand Down
2 changes: 1 addition & 1 deletion src/intro/objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ constructor list.
fully-constructed `Player` instance.
```

If your `T` contains a `#[base]` field, you cannot create a standalone `T` object -- you must encapsulate it in `Gd<T>`.
If your `T` contains a `Base<T>` field, you cannot create a standalone `T` object -- you must encapsulate it in `Gd<T>`.
You can also not extract a `T` from a `Gd<T>` smart pointer anymore; since it has potentially been shared with the Godot engine, this would
not be a safe operation.

Expand Down
1 change: 0 additions & 1 deletion src/recipes/custom-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ This workflow is similar to the [Hello World example][hello]:
#[derive(GodotClass)]
#[class(tool, init, base=Resource)]
struct ResourceType {
#[base]
base: Base<Resource>,
}
```
Expand Down
1 change: 0 additions & 1 deletion src/recipes/editor-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ you cannot introduce compile-time errors.
#[derive(GodotClass)]
#[class(tool, init, editor_plugin, base=EditorPlugin)]
struct MyEditorPlugin {
#[base]
base: Base<EditorPlugin>,
}

Expand Down
1 change: 0 additions & 1 deletion src/recipes/engine-singleton.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ Defining a singleton is the same as registering a custom class.
#[derive(GodotClass)]
#[class(tool, init, base=Object)]
struct MyEditorSingleton {
#[base]
base: Base<Object>,
}

Expand Down
20 changes: 10 additions & 10 deletions src/register/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,15 @@ store the instance of the Godot superclass (base class) as a field in our `Monst
struct Monster {
name: String,
hitpoints: i32,

#[base]
base: Base<Node3D>,
}
```

The `#[base]` attribute is currently necessary (as of January 2024), but will likely disappear in the future.

The important part is the `Base<T>` type. `T` must match the base class you specified in the `#[class(base=...)]` attribute.
You can also use the associated type `Self::Base` for `T`.

When you declare a base field in your struct, you can access the `Node` API through provided methods `self.base()` and `self.base_mut()`, but
more on this later.
When you declare a base field in your struct, the `#[derive]` procedural macro will automatically detect the `Base<T>` type.[^inference]
This lets you access the `Node` API through provided methods `self.base()` and `self.base_mut()`, but more on this later.


## Default constructor
Expand All @@ -121,8 +117,6 @@ You can use `#[class(init)]` to generate a constructor for you. This is limited
struct Monster {
name: String,
hitpoints: i32,

#[base]
base: Base<Node3D>,
}
```
Expand Down Expand Up @@ -157,8 +151,6 @@ We can provide a manually-defined constructor by overriding the trait's associat
struct Monster {
name: String,
hitpoints: i32,

#[base]
base: Base<Node3D>,
}

Expand Down Expand Up @@ -190,6 +182,14 @@ More on this topic in the next chapter.
You learned how to define a Rust class and register it with Godot. You now know how to select a base class and how to define a constructor.
The next chapter will allow you to implement logic by providing functions.

<br>

---

[^inference] You can tweak the type detection using the `#[hint]` attribute, see [the corresponding docs][api-derive-godotclass-inference].


[api-derive-godotclass]: https://godot-rust.github.io/docs/gdext/master/godot/register/derive.GodotClass.html
[api-derive-godotclass-inference]: https://godot-rust.github.io/docs/gdext/master/godot/register/derive.GodotClass.html#fine-grained-inference-hints
[api-godot-api]: https://godot-rust.github.io/docs/gdext/master/godot/register/attr.godot_api.html
[godot-gdscript-classes]: https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#classes
2 changes: 0 additions & 2 deletions src/register/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ So let's implement `to_string()`, here again showing the class definition for qu
struct Monster {
name: String,
hitpoints: i32,

#[base]
base: Base<Node3D>,
}

Expand Down

0 comments on commit 0ee1e6d

Please sign in to comment.