-
Notifications
You must be signed in to change notification settings - Fork 211
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
Simplify module structure II #811
Conversation
Most symbols appear directly in prelude without modules. There is 'user_data' nested, as it's used rarely and helps organize its types.
Planned changes in this PR:
Eventually I will squash some related commits, but possibly not all, as it's quite a big change. |
Overall I think it's a good idea to get rid of the deep nested import paths. I don't have any objections removing the
Regarding the planned changes:
This feels very confusing to me. The
Isn't this contrary to the effort of flattening nested modules? I think it's necessary to set the priorities clear for the task: do we want less symbols at each level, or a shallower hierarchy? These goals defeat each other. They cannot be achieved at the same time. Even with the current changes, I wouldn't say the top-level namespace is cluttered enough for this to be necessary.
I share the sentiment that there are shortcomings to the
Unless you want the top-level to be polluted by a bazillion generated types like it was in 0.8.x, |
Thanks a lot for your valuable feedback! 👍🏼
Agree to both. We could put
Ok, maybe I misunderstood the purpose, since it was explicitly in the
I don't see it as a single-dimensional optimization problem where we need to minimize nesting, or number of symbols per level. Important is that the grouping and organization is somewhat intuitive for the user, and that they find functionality they are looking for. Of course, that's very subjective and not easily quantifiable -- that's why we can't just automate these changes 🙂 In #788 I created a It looks like with the renaming of
So we have two options: create a top-level module for each of those, or try to somehow group them into a Could of course also be a mixed approach like: //! top-level lib.rs
mod global {
... // print + debug macros
... // entire init related functionality
// more advanced functionality in their own modules
mod log { ... }
mod profiler { ... }
} I don't have a very strong opinion here, maybe someone else can also give their input?
True, but unlike "core types" they are based in Godot's documentation and not chosen arbitrarily.
This wasn't an obstacle for Alternatives would be: "Simple types", "basic types", "primitives". More?
It definitely stays. What I meant is, if we should do something about duplicated symbols like class Camera2D {
public:
enum AnchorMode { ... };
enum Camera2DProcessMode { ... };
}; which then becomes in Rust: pub mod camera_2d {
pub struct Camera2D { ... }
pub struct AnchorMode { ... }
pub struct Camera2DProcessMode { ... }
}
pub use camera_2d::Camera2D; But again, it's a low-prio thing, would just be interesting to hear other people's opinions. |
Unless you rename the
I don't think I have seen many crates with a
I agree that the
Thanks for the clarification. Perhaps you can edit #811 (comment) to include this?
This reminds me: while we're at it, what do you think about renaming the One potential issue is collision with |
Makes sense 👍🏼
Yes, but the name varies. For "ubiquitious" functionality,
So everyone does it slightly differently. It seems to be that crates of larger scope (e.g. game or physics engines) tend to have fewer symbols directly on the top level.
Done 👍🏼
I assume you mean it collides with Generally we can do it, I would probably postpone it to #773 however (still v0.10.0), where we can also discuss removal/deprecation strategy. One thing to consider is how this concept is called with Godot 4 and GDExtension -- just so we don't need to rename it immediately again. |
I have checked all these crates:
Overall, I'd consider those examples very tangential.
Yes. Sorry for the confusion.
Sure, it can be postponed, but I wonder if there is any reason to consider Godot 4 naming, if GDExtension will be a divergent fork anyway? Wouldn't it be confusing to use Godot 4 names in a branch that will only support Godot 3.x? |
In general "others do it, so we should do it too" is not a particularly good argument, unless it's really industry-wide practice or we understand the reason why they're doing it. So I'm not trying to "prove" anything here, was merely trying to answer your question if I've seen this before 🙂 What I think is more relevant to decide this is:
The way we design implicitly sends a message on how important/accessible each symbol in the API is. Having more modules on the top level means the user probably devotes less attention to each. On the other hand, he directly sees profile/log information, which can be harder to discover otherwise. Ultimately it's a trade-off, but I agree it's a small one, and as you say we're not yet at a level where the top level is cluttered. So we can also start with this, and reorganize again if it becomes a problem.
I didn't mean to use Godot 4 names that have no meaning in Godot 3. Rather, if e.g. Godot 4 uses "native class" as the official term, so we now change it and break users code, only to break it again when they migrate to Godot 4. So, my thinking was more: "if we know a name that makes sense now and will still make sense in Godot 4, we might as well use that". Not a reason against Are there other potential candidates here? We usually talk about "exported methods/properties", does it make sense to extend this notion to classes/structs? |
I think this is a good idea. I think I showed up a bit late as I don't have anything new to add that chitoyuu hadn't already mentioned. Regarding core_types, it seems like the godot-cpp just files them all under |
I agree that keeping users' focus on the important stuff is an important aspect of API organization. When adding a new level of nesting, though, perhaps it's also worth it to consider the perspective of organic growth over time. For a Rust library, new modules are cheap to add, but existing ones are expensive to re-organize: this PR and #788 being the prime examples of this. It was organic growth that led us down this path of super-nested modules, and it will again if we don't start to artificially "price" new public modules at a higher point. Ultimately, we're still in 0.x with future breaking changes in the plans, so I concur that it isn't that big a problem even if we make some mistakes.
Ah, that makes sense! 👍 |
One argument in favor of I definitely think initialization-related symbols should be in their own module. They're usually only ever used in one file in a project. In mine, I use them in every Logging and profiling seem related-enough to printing and debugging to be together IMO... Although printing and debugging are so common that it could make a lot of sense to put them in the root of the crate, but I'm not sure the same could be said for logging/profiling.
Does the parent class actually need to be defined in the module at all? Is this just due to how the bindings generator works, or is there some other reason for it? Could it just be: pub mod camera_2d {
pub struct AnchorMode { ... }
pub struct Camera2DProcessMode { ... }
}
pub struct Camera2D { ... } One other related thought that hasn't been brought up yet: Is there any way we could make the global constants available in a module, instead of associated with the |
Thanks for your input as well, Waridley! Regarding
Would also be possible. The slight disadvantage is that one has to import 2 different modules when dealing with 1 specific class, but I'd say that's OK. It should still be clear which
Are these the same symbols as documented in Yes, I think this should be doable, and would allow importing instead of qualifying the struct. Will need changes in the code generator, so probably out of scope for this refactoring. Could you open a separate issue for it? |
60d50d2
to
2f50d62
Compare
That's true. Personally I'd like this trade-off, but I'd definitely understand if not everyone else liked it. I won't complain either way 🙂 I don't think I have any other feedback; I like what you're doing! My imports are a mess right now 😆 |
33ce43b
to
c9a5b84
Compare
Implemented most of the changes, will do the rest later today or tomorrow. Pending / to be discussed:
|
Changes: * Move out symbols from export::{method, property} * Flatten property::accessor::invalid * Rename Usage -> PropertyUsage (like the already re-exported version)
0c38cec
to
54ac19c
Compare
54ac19c
to
c4c5281
Compare
bors try |
tryBuild succeeded: |
Edited initial post to give an up-to-date overview of the changes. |
c4c5281
to
af2e1f5
Compare
bors try |
tryBuild succeeded: |
Sorry for the late comment! I agree we can go ahead and merge this in. I think the renaming is something we can decide on later (perhaps by vote). |
…itional types (not the API class itself)
…e empty nested modules
Removed: * godot_gdnative_init * godot_gdnative_terminate * godot_nativescript_init * godot_site Also documented prelude::user_data
af2e1f5
to
a451e1b
Compare
bors r+ |
811: Simplify module structure II r=Bromeon a=Bromeon This PR is a continuation of #788 and addresses the remaining, somewhat ambitious tasks for module cleanup. Goals: * Every symbol appears at most once in prelude * Every symbol appears at exactly once outside prelude * 2-3 modules (inside the crate) are the maximum nesting depth * Modules named according to related functionality from user point of view Changes: 1. `nativescript` module * Rename to `export`. Rationale: "native script" is quite a wide term, while most the module's current functionality is directly related to _exporting_ symbols from Rust. In practice, godot-rust is always (?) used as a native script. Other potential use cases, as a pure Godot API library or with native_calls, seem to be the exception, if at all. * Along with renaming, the `nativescript` feature is removed. * Nested symbols in `export::{properties, methods}` are moved one level up. * As a result, we can avoid very long qualifiers and multiple candidates for `use` statements. * `nativescript::init::property::hint::EnumHint` -> `export::hint::EnumHint` * `nativescript::export::method::MethodBuilder` -> `export::MethodBuilder` 1. `api` module * Remove inner types like `api::area::Area`, as they are already present in `api`. * Remove all modules which would then become empty. * Create doc links between class (`Camera2D`) and related module (`camera_2d`). 1. Smaller top-level modules * Add `init` (previously part of `nativescript`). * Add `profiler` (previously part of `nativescript`). * Extend `log` with related macros. * Remove `macros` and distribute its symbols to the most fitting API. 1. `prelude` module * Remove a few macros (`godot_gdnative_init` etc.) from the prelude, suggesting that `godot_init` should be used. * `user_data` symbols are accessible through `prelude::user_data` instead of `prelude` directly. This mirrors common usage in examples. 1. `core_types` module No changes in this PR; see PR discussion for reasons and potential alternatives. Co-authored-by: Jan Haller <[email protected]>
Canceled. |
Added commit to fix warning with bors r+ |
Build succeeded: |
[Edit] Results are now visible on https://godot-rust.github.io/docs.
This PR is a continuation of #788 and addresses the remaining, somewhat ambitious tasks for module cleanup.
Goals:
Changes:
nativescript
moduleexport
. Rationale: "native script" is quite a wide term, while most the module's current functionality is directly related to exporting symbols from Rust. In practice, godot-rust is always (?) used as a native script. Other potential use cases, as a pure Godot API library or with native_calls, seem to be the exception, if at all.nativescript
feature is removed.export::{properties, methods}
are moved one level up.use
statements.nativescript::init::property::hint::EnumHint
->export::hint::EnumHint
nativescript::export::method::MethodBuilder
->export::MethodBuilder
api
moduleapi::area::Area
, as they are already present inapi
.Camera2D
) and related module (camera_2d
).Smaller top-level modules
init
(previously part ofnativescript
).profiler
(previously part ofnativescript
).log
with related macros.macros
and distribute its symbols to the most fitting API.prelude
modulegodot_gdnative_init
etc.) from the prelude, suggesting thatgodot_init
should be used.user_data
symbols are accessible throughprelude::user_data
instead ofprelude
directly. This mirrors common usage in examples.core_types
moduleNo changes in this PR; see PR discussion for reasons and potential alternatives.